I have an ansible playbook that I run from below command line and it works fine.
ansible-playbook -e 'host_key_checking=False' -e 'num_serial=10' test.yml -u golden
It works on the hosts specified in /etc/ansible/hosts file. But is there any way to pass hostnames directly on the command line or generate new file with hostname line by line in it so that my ansible works on that hostnames instead of working from default /etc/ansible/hosts file?
Below is my ansible file:
# This will copy files
---
- hosts: servers
serial: "{{ num_serial }}"
tasks:
- name: copy files to server
shell: "(ssh -o StrictHostKeyChecking=no abc.host.com 'ls -1 /var/lib/workspace/data/*' | parallel -j20 'scp -o StrictHostKeyChecking=no abc.host.com:{} /data/holder/files/procs/')"
- name: sleep for 3 sec
pause: seconds=3
Now I wanted to generate new file which will have all the servers line by line and then my ansible play book work on that file instead? Is this possible?
I am running ansible 2.6.3 version.
The question has been answered probably but will just answer again to add more points.
Always look for command line for help related to the arguments or any info needed.
ansible-playbook --help | grep inventory
-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
specify inventory host path or comma separated host
list. --inventory-file is deprecated
The support of ansible inventory in file format is with two extensions:
yml
ini --> specifying ini extension is not mandatory.
The inventory link provides more info on the format and should be referred before choosing any format to implement.
Adding #HermanTheGermanHesse answer's so that all the possible points are covered.
In case the above is not used/you don't want to use. Ansible at last will refer the ansible.cfg for the hosts and variable definition.
[defaults]
inventory = path/to/hosts
From here:
The ansible.cfg file will be chosen in this order:
ANSIBLE_CONFIG environment variable
/ansible.cfg
~/.ansible.cfg
/etc/ansible/ansible.cfg
You can use the -i flag to specify the inventory to use. For example:
ansible-playbook -i hosts play.yml
A way to specify the inventory file to use is to set inventory in the ansible.cfg-file as such:
[defaults]
inventory = path/to/hosts
From here:
The ansible.cfg file will be chosen in this order:
ANSIBLE_CONFIG environment variable
./ansible.cfg
~/.ansible.cfg
/etc/ansible/ansible.cfg
EDIT
From your comment:
[WARNING]: Could not match supplied host pattern, ignoring: servers PLAY [servers]
It seems that ansible doesn't recognize hosts passed with the -i Flag as belonging to a group. Since you mentioned in chat that you generate a list with the passed hosts, I'd suggest creating a file where the list of hosts to passed is made to belong to a group callerd [servers] and passing the path to it with the -i Flag.
I am new to Ansible and trying to learn the basics. But apparently I already fail with setting up the inventory file.
For the setup:
1) Installed ansible via homebrew
2) as no ansible.cfg was created, I created one manually in /etc/ansible/ansible.cfg
ansible.cfg
[defaults]
inventory = /etc/ansible/hosts/;
3) a hosts file was also not there, so I created the same in /etc/ansible/hosts
hosts
Test1
Test2
When I run ansible all --list-hosts I get the error:
[WARNING]: Unable to parse /etc/ansible/hosts; as an inventory source
As the path is correctly reflected in the error, I at least assume, the cfg is read correctly. But still the target file hosts is not being recognized. I tried differennt paths. What do I need to change?
remove /; from the end of the inventory-line in /etc/ansible/ansible.cfg:
cat /etc/ansible/ansible.cfg
[defaults]
inventory = /etc/ansible/hosts
you could use ansible -i /etc/ansible/hosts to tell ansible use this inventory file.
I'm quite new to ansible and i have a new problem recently. I try to run the playbook and below is the error i get.
[bhar1#desktop ~]$ ansible-playbook -i inv abc.yaml -vvv
ansible-playbook 2.4.2.0
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/bhar1/.ansible/plugins /modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages /ansible
executable location = /bin/ansible-playbook
python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
Using /etc/ansible/ansible.cfg as config file
[WARNING]: Unable to parse /home/bhar1/inv as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: Could not match supplied host pattern, ignoring: all
[WARNING]: provided hosts list is empty, only localhost is available
PLAYBOOK: abc.yaml **********************************************************************************************************************************
1 plays in abc.yaml
[WARNING]: Could not match supplied host pattern, ignoring: webservers
PLAY [webservers] ***********************************************************************************************************************************
skipping: no hosts matched
PLAY RECAP ******************************************************************************************************************************************
Can you please help me explain what could be the reason for this. My /etc/ansible/hosts file is updates with webservers group as we. Below is the yml file.
[bhar1#desktop ~]$ cat abc.yaml
---
- hosts: webservers
become: yes
tasks:
- name: remove httpd
yum:
name: httpd
state: absent
[bhar1#desktop ~]$
If you have updated the host group in /etc/ansible/hosts , you need to pass the path with -i, you have passed wrong file as i see its empty , use below and see if it works
ansible-playbook -i /etc/ansible/hosts abc.yaml
Error is displayed because Ansible is unable to find your inventory file.
To execute the playbook abc.yaml, run the following command:
ansible-playbook -i /etc/ansible/hosts abc.yaml
Execution tells the ansible to use inventory file available in /etc/ansible/hosts and to parse playbook file "abc.yaml".Inventory argument -i is used to pass the inventory path.
it seems that ansible looking for wrong inventory file.
does this file "/home/bhar1/inv" exist?
if not, then you should use:
ansible-playbook -i [/path/to/inventory_file] abc.yaml -vvv
I am trying to do some testing against a specific host with Ansible 2.5 but ansible can't figure out my inventory. I've either done something wrong or there's a bug. I've done this in the past but maybe something changed in 2.5
I have an inventory file specified like this:
localhost ansible_connection=local
testhost ansible_ssh_host=1.2.3.4
I have a playbook that runs totally fine if i just run it with ansible playbook.yml. It starts like this:
- hosts: localhost
become: yes
become_user: root
become_method: sudo
gather_facts: yes
If I run ansible-inventory --list I see both of my hosts listed as "ungrouped"
However, if I try to run my playbook against the remote host using ansible -l testhost playbook.yml it errors with the following:
[WARNING]: Could not match supplied host pattern, ignoring: playbook.yml
ERROR! Specified hosts and/or --limit does not match any hosts
I can't figure out how to actually make Ansible run against my remote host.
Your playbook specifies:
hosts: localhost
It will not run on testfile regardless of the arguments you supply. --limit does not replace the hosts declaration.
As your hosts are ungrouped, you need to change this to:
hosts: all
Then you can use limit option to filter the hosts from the given target group.
You are also using wrong command to run an Ansible playbook, it should be ansible-playbook not ansible (and although the effect is the same, the latter does not fail with an error in such case).
use simple method wherever you have to connect on local system? just specify connection : local to hosts block
- hosts: localhost
connection : local
become: yes
become_user: root
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>