I am running the following ansible playbook
- hosts: localhost
connection: local
vars_files:
- vars/config_values.yaml
gather_facts: no
tasks:
- name: Set correct project in gcloud config
shell: "gcloud config set project {{ google_project_name }}"
Which yields the following warning:
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
Given that I am explicitly stating that it will be run against host: localhost, why is it complaining about no inventory being parsed and that the "provided host list is empty"?
How to remove these warnings? (without just suppressing them if possible)
These are just warnings telling you that:
you did not provide any inventory file either with the -i option, in your ansible.cfg or by default in /etc/ansible/hosts (and hence none was parsed and it is empty)
your inventory is empty and hence only the implicit localhost is available (reminding you that it does not match the all group)
additional notes
hosts: localhost in your above playbook example is the target for your play. It could be an other host or a group (or a more complicated pattern). The targeted hosts must exist in the inventory to be managed. localhost always exists at least as the implicit local machine.
You can read Ansible introduction to inventories for more information
Although those two warning seem a bit redundant, they give different information (i.e. "no inventory at all" vs "inventory is simply empty"). As such they are governed by different config options
The second warning can be silenced since ansible v2.6 with the LOCALHOST_WARNING option
The first warning can be silenced since ansible-core v2.14 with the INVENTORY_UNPARSED_WARNING option
For the records, the first feature as been added to Ansible by a pull request proposed by #larsk, a stackoverflow user
So if you intend to run playbooks primarily targeted to localhost without giving any inventory to parse, you can silence both warnings as in the following one-liner (see links above for all options to set those vars)
ANSIBLE_LOCALHOST_WARNING=False \
ANSIBLE_INVENTORY_UNPARSED_WARNING=False \
ansible-playbook your_localhost_playbook.yml
As a non-expert. in Ansible, I suppressed these messages by adding localhost on the /etc/ansible/hosts. Then set hosts: localhost on the playbook file. You should be good and won't be seeing those warning messages.
Hosts file
[ec2-user#ip-192-168-1-38 ~]$ sudo head -20 /etc/ansible/hosts
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups
# Ex 1: Ungrouped hosts, specify before any group headers.
localhost
## green.example.com
## blue.example.com
## 192.168.100.1
## 192.168.100.10
# Ex 2: A collection of hosts belonging to the 'webservers' group
## [webservers]
Playbook file
[ec2-user#ip-192-168-1-38 ~]$ cat msteams.yml
- name: MSTeams
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: MSTeams Sending
uri:
url: https://outlook.office.com/webhook/asdasda-asdasd-40sdfd-btryrty2-posadjfm,sdnfoersmdnrfoasf,mvmnmtrny40956839523842/IncomingWebhook/102938091283kdjoasdyo214/vnmlasdhfaosldnaehywe
method: POST
body: "{\"text\": \"**Header:** {{Header}}\n\n **Next Line Message1:** {{MESSAGE1}}\n\n **Next Line Message2:** '{{ MESSAGE2 }}'\", \"themeColor\": \"{{COLOR}}\"}"
body_format: json
headers:
Content-Type: "application/json"
Command Result
[ec2-user#ip-192-168-1-38 ~]$ ansible-playbook msteams.yml -e "Header=TEST" -e "MESSAGE1=Message_without_space" -e ' MESSAGE2="Message with space" ' -e "COLOR=##FF0000"
PLAY [MSTeams] ***********************************************************************************************************************************************************************************************
TASK [MSTeams Sending] ************************************************************************************************************************************************************************************
ok: [localhost]
PLAY RECAP ****************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
As of ansible 2.6 you can also run ANSIBLE_LOCALHOST_WARNING=false ansible-playbook /path/to/your/playbook.yaml or set "localhost_warning=false" in your ansible.cfg file
https://docs.ansible.com/ansible/latest/reference_appendices/config.html#localhost-warning
I'm passing the IP as parameter as mentioned here: https://stackoverflow.com/a/18255256/1784001
ansible-playbook roles/example/main.yml -i 127.0.0.1,
Is there any way to access the value for the inventory parameter, "127.0.0.1" in a playbook?
I checked the special variables, but I see no mention of it: https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html
In some of the tasks I need that value, for example creating backup directories, or scp-ing to the host.
inventory_hostname always contains the inventory hostname of the host the play is running at.
The parameter -i "specify inventory host path or comma separated host list." Running the playbook main.yml
- hosts: all
tasks:
- debug: var=inventory_hostname
With the command
$ ansible-playbook -i 127.0.0.1, main.yml
gives
ok: [127.0.0.1] =>
inventory_hostname: 127.0.0.1
I do not wish to specify any hosts file to ansible-playbook command.
ansible-playbook site.yml -e "source_host=mymac1 source_file=myfile1"
My site.yml looks like this:
more site.yml
---
- hosts: "{{ source_host | default('my_pc')}}"
user: weblogic
However, I get the following error:
[WARNING]: Could not match supplied host pattern, ignoring: all
[WARNING]: provided hosts list is empty, only localhost is available
PLAYBOOK: site.yml
********************************************************************************************************************************************************************************** 2 plays in site.yml [WARNING]: Could not match supplied host pattern,
ignoring: mymac1
Can you please suggest how can i pass any host to my playbook without having to maintain and host respository with all the host information
I am on ansible version 2.3.1.0
You can use inline inventory:
playbook.yml:
- hosts: all
tasks:
- debug: msg=hello
command:
ansible-playbook -i 'mymac1,' -e source_file=myfile1 playbook.yml
note comma after hostname.
Also see: Ansible ad-hoc command with direct host specified - no hosts matched
quick question for Ansible Guru's. I want to run an ansible playbook for a specific set of boxes that I copied to a list.txt disregarding the inventory and the target block in ansible playbook:
---
- name: Ansible Runbook v.1.0
hosts: test1
gather_facts: yes
# serial: "10%"
When I am running the following command I am getting no hosts matched:
ansible-playbook playbook.yaml --tags "simplejson" -vvv -i /x/home/list.txt
PLAY [Ansible Runbook v.1.0] **************************************************
skipping: no hosts matched
$cat list.txt
hostname2b
Any ideas for a workaround ?
The reason of no host matching is that host test1, which is hardcoded in playbook, is not present in the inventory file that you specified from command line. The problem is ansible-playbook command does not accept any hosts parameter. So there is no direct way of getting around the hardcoded hosts test1.
However, there is a workaround for this as explained here. You can use a variable for hosts and specify all from command line for that variable. Something like this:
---
- name: Ansible Runbook v.1.0
hosts: "{{ host_param }}"
gather_facts: yes
Then pass that variable with extra-vars:
ansible-playbook playbook.yaml -i /x/home/list.txt --extra-vars="host_param=all" --tags "simplejson" -vvv
I'm using Ansible for some simple user management tasks with a small group of computers. Currently, I have my playbooks set to hosts: all and my hosts file is just a single group with all machines listed:
# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local
I've found myself frequently having to target a single machine. The ansible-playbook command can limit plays like this:
ansible-playbook --limit imac-2.local user.yml
But that seems kind of fragile, especially for a potentially destructive playbook. Leaving out the limit flag means the playbook would be run everywhere. Since these tools only get used occasionally, it seems worth taking steps to foolproof playback so we don't accidentally nuke something months from now.
Is there a best practice for limiting playbook runs to a single machine? Ideally the playbooks should be harmless if some important detail was left out.
Turns out it is possible to enter a host name directly into the playbook, so running the playbook with hosts: imac-2.local will work fine. But it's kind of clunky.
A better solution might be defining the playbook's hosts using a variable, then passing in a specific host address via --extra-vars:
# file: user.yml (playbook)
---
- hosts: '{{ target }}'
user: ...
Running the playbook:
ansible-playbook user.yml --extra-vars "target=imac-2.local"
If {{ target }} isn't defined, the playbook does nothing. A group from the hosts file can also be passed through if need be. Overall, this seems like a much safer way to construct a potentially destructive playbook.
Playbook targeting a single host:
$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts
playbook: user.yml
play #1 (imac-2.local): host count=1
imac-2.local
Playbook with a group of hosts:
$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts
playbook: user.yml
play #1 (office): host count=3
imac-1.local
imac-2.local
imac-3.local
Forgetting to define hosts is safe!
$ ansible-playbook user.yml --list-hosts
playbook: user.yml
play #1 ({{target}}): host count=0
There's also a cute little trick that lets you specify a single host on the command line (or multiple hosts, I guess), without an intermediary inventory:
ansible-playbook -i "imac1-local," user.yml
Note the comma (,) at the end; this signals that it's a list, not a file.
Now, this won't protect you if you accidentally pass a real inventory file in, so it may not be a good solution to this specific problem. But it's a handy trick to know!
This approach will exit if more than a single host is provided by checking the play_hosts variable. The fail module is used to exit if the single host condition is not met. The examples below use a hosts file with two hosts alice and bob.
user.yml (playbook)
---
- hosts: all
tasks:
- name: Check for single host
fail: msg="Single host check failed."
when: "{{ play_hosts|length }} != 1"
- debug: msg='I got executed!'
Run playbook with no host filters
$ ansible-playbook user.yml
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
failed: [alice] => {"failed": true}
msg: Single host check failed.
failed: [bob] => {"failed": true}
msg: Single host check failed.
FATAL: all hosts have already failed -- aborting
Run playbook on single host
$ ansible-playbook user.yml --limit=alice
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
skipping: [alice]
TASK: [debug msg='I got executed!'] ***************************************
ok: [alice] => {
"msg": "I got executed!"
}
There's IMHO a more convenient way.
You can indeed interactively prompt the user for the machine(s) he wants to apply by using vars_prompt:
---
- hosts: "{{ setupHosts }}"
vars_prompt:
- name: "setupHosts"
prompt: "Which hosts would you like to setup?"
private: false
tasks:
- shell: echo
A slightly different solution is to use the special variable ansible_limit which is the contents of the --limit CLI option for the current execution of Ansible.
- hosts: "{{ ansible_limit | default(omit) }}"
No need to define an extra variable here, just run the playbook with the --limit flag.
ansible-playbook --limit imac-2.local user.yml
To expand on joemailer's answer, if you want to have the pattern-matching ability to match any subset of remote machines (just as the ansible command does), but still want to make it very difficult to accidentally run the playbook on all machines, this is what I've come up with:
Same playbook as the in other answer:
# file: user.yml (playbook)
---
- hosts: '{{ target }}'
user: ...
Let's have the following hosts:
imac-10.local
imac-11.local
imac-22.local
Now, to run the command on all devices, you have to explicty set the target variable to "all"
ansible-playbook user.yml --extra-vars "target=all"
And to limit it down to a specific pattern, you can set target=pattern_here
or, alternatively, you can leave target=all and append the --limit argument, eg:
--limit imac-1*
ie.
ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts
which results in:
playbook: user.yml
play #1 (office): host count=2
imac-10.local
imac-11.local
I really don't understand how all the answers are so complicated, the way to do it is simply:
ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check
The check mode allows you to run in dry-run mode, without making any change.
AWS users using the EC2 External Inventory Script can simply filter by instance id:
ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts
This works because the inventory script creates default groups.
Since version 1.7 ansible has the run_once option. Section also contains some discussion of various other techniques.
We have some generic playbooks that are usable by a large number of teams. We also have environment specific inventory files, that contain multiple group declarations.
To force someone calling a playbook to specify a group to run against, we seed a dummy entry at the top of the playbook:
[ansible-dummy-group]
dummy-server
We then include the following check as a first step in the shared playbook:
- hosts: all
gather_facts: False
run_once: true
tasks:
- fail:
msg: "Please specify a group to run this playbook against"
when: '"dummy-server" in ansible_play_batch'
If the dummy-server shows up in the list of hosts this playbook is scheduled to run against (ansible_play_batch), then the caller didn't specify a group and the playbook execution will fail.
This shows how to run the playbooks on the target server itself.
This is a bit trickier if you want to use a local connection. But this should be OK if you use a variable for the hosts setting and in the hosts file create a special entry for localhost.
In (all) playbooks have the hosts: line set to:
- hosts: "{{ target | default('no_hosts')}}"
In the inventory hosts file add an entry for the localhost which sets the connection to be local:
[localhost]
127.0.0.1 ansible_connection=local
Then on the command line run commands explicitly setting the target - for example:
$ ansible-playbook --extra-vars "target=localhost" test.yml
This will also work when using ansible-pull:
$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml
If you forget to set the variable on the command line the command will error safely (as long as you've not created a hosts group called 'no_hosts'!) with a warning of:
skipping: no hosts matched
And as mentioned above you can target a single machine (as long as it is in your hosts file) with:
$ ansible-playbook --extra-vars "target=server.domain" test.yml
or a group with something like:
$ ansible-playbook --extra-vars "target=web-servers" test.yml
I have a wrapper script called provision forces you to choose the target, so I don't have to handle it elsewhere.
For those that are curious, I use ENV vars for options that my vagrantfile uses (adding the corresponding ansible arg for cloud systems) and let the rest of the ansible args pass through. Where I am creating and provisioning more than 10 servers at a time I include an auto retry on failed servers (as long as progress is being made - I found when creating 100 or so servers at a time often a few would fail the first time around).
echo 'Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'
echo ' bootstrap - Bootstrap servers ssh port and initial security provisioning'
echo ' dev - Provision localhost for development and control'
echo ' TARGET - specify specific host or group of hosts'
echo ' all - provision all servers'
echo ' vagrant - Provision local vagrant machine (environment vars only)'
echo
echo 'Environment VARS'
echo ' BOOTSTRAP - use cloud providers default user settings if set'
echo ' TAGS - if TAGS env variable is set, then only tasks with these tags are run'
echo ' SKIP_TAGS - only run plays and tasks whose tags do not match these values'
echo ' START_AT_TASK - start the playbook at the task matching this name'
echo
ansible-playbook --help | sed -e '1d
s#=/etc/ansible/hosts# set by bin/provision argument#
/-k/s/$/ (use for fresh systems)/
/--tags/s/$/ (use TAGS var instead)/
/--skip-tags/s/$/ (use SKIP_TAGS var instead)/
/--start-at-task/s/$/ (use START_AT_TASK var instead)/
'
I would suggest using --limit <hostname or ip>