Exclude a group that contains localhost - ansible

Given the following inventory :
[group1]
myserver.domain.com ansible_ssh_user=myUser
[group2]
localhost ansible_connection=local
How can I only execute my playbook on the group1 host(s) ?
When I use --limit=group1, it also includes localhost
I tried --limit='!group2', it does not work either.
Any idea?
Thx in advance
EDIT:
I am using ansible 1.9.2.

I can't test it on your ansible version. I suggest you a workaround changing the target host definition in your playbook as follows:
So you'll have something like this
- name: Test limit
hosts: "{{ hosts_nodes | default('all')}}"
tasks:
- file: path=/tmp/mydir state=directory
and running the playbook adding the additional environment variable hosts_nodes
ansible-playbook -i test.inventory test.yml -e hosts_nodes=group1

What ansible version are you using? It works correclty in version 2.1.2.0.
This is my test.inventory file
[group1]
myserver.domain.com ansible_ssh_user=myUser
[group2]
localhost ansible_connection=local
This is my test playbook test.yml
- name: Test limit
hosts: all
tasks:
- file: path=/tmp/mydir state=directory
I get what expected both running
ansible-playbook -i test.inventory --limit group2 test.yml
and
ansible-playbook -i test.inventory --limit '!group1' test.yml

Related

Ansible control node - can it configure itself?

I'm just getting into using Ansible - please be patient if this question is misguided.
I have a handful of servers on a network, one of which I plan to setup as the control node (Rhel7.9). I would like to use ansible locally on that system to configure itself using a few playbooks of interest, and do this as a sort of test before rolling out to other systems. I'm in the process of setting up my ansible config and inventory - from everything I'm reading it makes it seem like ansible is designed to simply push configurations to managed nodes... rather than do a 1 time run for the machine you are on.
What if I would simply like to pull a playbook from ansible galaxy and run it locally on the control node?
Would this as simple as running:
ansible-playbook -i "localhost," -c local playbook.yml
Do I even need to setup inventory and config to do this for the machine I am on? Are there best practices I'm missing because of my noobity?
Thanks!
Q: "Pull a playbook from Ansible Galaxy and run it locally on the control node."
A: Yes. For example the playbook
shell> cat playbook.yml
- hosts: all
gather_facts: false
tasks:
- debug:
var: inventory_hostname
is as simple as running
shell> ansible-playbook playbook.yml -i localhost,
PLAY [all] **********************************************************************
TASK [debug] ********************************************************************
ok: [localhost] =>
inventory_hostname: localhost
...
Best practice
Review the playbook and make sure you understand what the playbook is going to configure.
Check the syntax first
shell> ansible-playbook playbook.yml -i localhost, --syntax-check
Dry run the playbook and show the changes
shell> ansible-playbook playbook.yml -i localhost, --check --diff
If you think all is right run the playbook
shell> ansible-playbook playbook.yml -i localhost,
Privilage escalation
Run Ansible as a user and become root. See the link above on how to do it. For example, edit the playbook
shell> cat playbook.yml
- hosts: localhost
gather_facts: false
become: true
tasks:
- command: ls -la /root/.ssh
register: result
- debug:
var: result.stdout_lines

How to Skip hosts repository and specify host Runtime in Ansible

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

Make Ansible included playbooks run on same hosts as their parent

Helllo, what is the best way to make an included playbook run on the same hosts as the playbook that called him?
I've tried declaring a variable in the parent playbook with the host name and then passing it to the included playbook, but I get an error telling me that the variable is undefined.
Below is my playbook:
---
# Main staging configuration playbook
- vars:
host_name: "stage_ansible"
hosts: "{{ host_name }}"
remote_user: ubuntu
tasks:
- name: test connection
ping:
remote_user: ubuntu
- include: NginxDefinitions.yml
vars:
service_name: "interaction.qmerce.com"
env_name: "stage4"
host_name_pass: "{{ host_name }}"
...
and the error I'm receiving:
`ERROR! 'host_name' is undefined
If you want to define the hosts runtime and avoid hard coding them on the playbook, you can pass the hosts as extra variables on the command line.
To do so, remove vars definition from your first play and add the following to the ansible-playbook command line:
--extra-vars host_name=localhost
or when you have multiple hosts:
--extra-vars '{"host_name":["host1","host2","host3"]}'

Ansible playbook run for the servers in the list

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

Override hosts variable of Ansible playbook from the command line

This is a fragment of a playbook that I'm using (server.yml):
- name: Determine Remote User
hosts: web
gather_facts: false
roles:
- { role: remote-user, tags: [remote-user, always] }
My hosts file has different groups of servers, e.g.
[web]
x.x.x.x
[droplets]
x.x.x.x
Now I want to execute ansible-playbook -i hosts/<env> server.yml and override hosts: web from server.yml to run this playbook for [droplets].
Can I just override as a one time off thing, without editing server.yml directly?
Thanks.
I don't think Ansible provides this feature, which it should. Here's something that you can do:
hosts: "{{ variable_host | default('web') }}"
and you can pass variable_host from either command-line or from a vars file, e.g.:
ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
For anyone who might come looking for the solution.
Play Book
- hosts: '{{ host }}'
tasks:
- debug: msg="Host is {{ ansible_fqdn }}"
Inventory
[web]
x.x.x.x
[droplets]
x.x.x.x
Command: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets"
So you can specify the group name in the extra-vars
We use a simple fail task to force the user to specify the Ansible limit option, so that we don't execute on all hosts by default/accident.
The easiest way I found is this:
---
- name: Force limit
# 'all' is okay here, because the fail task will force the user to specify a limit on the command line, using -l or --limit
hosts: 'all'
tasks:
- name: checking limit arg
fail:
msg: "you must use -l or --limit - when you really want to use all hosts, use -l 'all'"
when: ansible_limit is not defined
run_once: true
Now we must use the -l (= --limit option) when we run the playbook, e.g.
ansible-playbook playbook.yml -l www.example.com
Limit option docs:
Limit to one or more hosts This is required when one wants to run a
playbook against a host group, but only against one or more members of
that group.
Limit to one host
ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1"
Limit to multiple hosts
ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1,host2"
Negated limit.
NOTE: Single quotes MUST be used to prevent bash
interpolation.
ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'all:!host1'
Limit to host group
ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'group1'
This is a bit late, but I think you could use the --limit or -l command to limit the pattern to more specific hosts. (version 2.3.2.0)
You could have
- hosts: all (or group)
tasks:
- some_task
and then ansible-playbook playbook.yml -l some_more_strict_host_or_pattern
and use the --list-hosts flag to see on which hosts this configuration would be applied.
An other 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) }}"
If the --limit option is omitted, then Ansible issues a warning, but does nothing since no host matched.
[WARNING]: Could not match supplied host pattern, ignoring: None
PLAY ****************************************************************
skipping: no hosts matched
I'm using another approach that doesn't need any inventory and works with this simple command:
ansible-playbook site.yml -e working_host=myhost
To perform that, you need a playbook with two plays:
first play runs on localhost and add a host (from given variable) in a known group in inmemory inventory
second play runs on this known group
A working example (copy it and runs it with previous command):
- hosts: localhost
connection: local
tasks:
- add_host:
name: "{{ working_host }}"
groups: working_group
changed_when: false
- hosts: working_group
gather_facts: false
tasks:
- debug:
msg: "I'm on {{ ansible_host }}"
I'm using ansible 2.4.3 and 2.3.3
I changed mine to default to no host and have a check to catch it. That way the user or cron is forced to provide a single host or group etc. I like the logic from the comment from #wallydrag. The empty_group contains no hosts in the inventory.
- hosts: "{{ variable_host | default('empty_group') }}"
Then add the check in tasks:
tasks:
- name: Fail script if required variable_host parameter is missing
fail:
msg: "You have to add the --extra-vars='variable_host='"
when: (variable_host is not defined) or (variable_host == "")
Just came across this googling for a solution. Actually, there is one in Ansible 2.5. You can specify your inventory file with --inventory, like this: ansible --inventory configs/hosts --list-hosts all
If you want to run a task that's associated with a host, but on different host, you should try delegate_to.
In your case, you should delegate to your localhost (ansible master) and calling ansible-playbook command
I am using ansible 2.5 (2.5.3 exactly), and it seems that the vars file is loaded before the hosts param is executed. So you can set the host in a vars.yml file and just write hosts: {{ host_var }} in your playbook
For example, in my playbook.yml:
---
- hosts: "{{ host_name }}"
become: yes
vars_files:
- vars/project.yml
tasks:
...
And inside vars/project.yml:
---
# general
host_name: your-fancy-host-name
Here's a cool solution I came up to safely specify hosts via the --limit option. In this example, the play will end if the playbook was executed without any hosts specified via the --limit option.
This was tested on Ansible version 2.7.10
---
- name: Playbook will fail if hosts not specified via --limit option.
# Hosts must be set via limit.
hosts: "{{ play_hosts }}"
connection: local
gather_facts: false
tasks:
- set_fact:
inventory_hosts: []
- set_fact:
inventory_hosts: "{{inventory_hosts + [item]}}"
with_items: "{{hostvars.keys()|list}}"
- meta: end_play
when: "(play_hosts|length) == (inventory_hosts|length)"
- debug:
msg: "About to execute tasks/roles for {{inventory_hostname}}"
This worked for me as I am using Azure devops to deploy an application using CICD pipelines. I had to make this hosts (in yml file) more dynamic so in release pipeline I can add it's value, for example:
--extra-vars "host=$(target_host)"
pipeline_variable
My ansible playbook looks like this
- name: Apply configuration to test nodes
hosts: '{{ host }}'

Resources