How to identify the hosts in my playbook from a variable file? - ansible-inventory

on my hosts file, I have like 10 different groups that each has devices in it. each customer deployment, should go to a specific region and I want to specify that in a customer config file.
In my playbook, I tried to use a variable in front of hosts and my plan was to specify the hosts group in the config file.
master_playbook.yml
hosts: "{{ target_region }}"
vars:
custom_config_file: "./app_deployment/customer_config_files/xx_app_prod.yml"
xx_app_prod.yml
customer: test1
env: prod
app_port: 25073
target_region: dev
Error message I get:
ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'target_region' is undefined

To determine a HOST(who is not the running host) in which groups he is in u have to use a little helper:
Create a script:
#!/usr/bin/env ansible-playbook
#call like: ./showgroups -i develop -l jessie.fritz.box
- hosts: all
gather_facts: no
tasks:
- name: show the groups the host(s) are in
debug:
msg: "{{group_names}}"
After that u can run a Playbook Like:
- name: "get group memberships of host"
shell: "{{ role_path }}/files/scripts/show_groups -i {{ fullinventorypath }} -l {{ hostname }}"
register: groups
- name: "create empty list of group memberships"
set_fact:
memberships: []
- name: "fill list"
set_fact:
memberships: "{{ memberships + item }}"
with_items: groups.stdout.lines

Related

Issue running an ansible playbook in WSL2/Ubuntu that runs fine in MacOS

I have a tcpdump.yaml file that I and the rest of my team are able to run just fine in a terminal in VSCode (and Atom) on Mac, but when I try to run the same playbook on my Windows laptop, I get several fatal errors related to variable. This playbook runs without error on the other machines for our team, and I am waiting for my Mac to come in, but I would like to get this working in the mean time.
fatal: [sample-dev-04]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ tcpdump.stdout_lines | regex_search('10.[0-9]+.[0-9]+.[0-9]+') }}): expected string or bytes-like object"}
fatal: [sample-dev-04]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'tcpdump_switch' is undefined\n\nThe error appears to be in '/home/testuser/.ansible/testcode/Playbooks/tcpdump.yaml': line 21, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Print tcpdump relevant information\n ^ here\n"}
Here is the code in question. The first 3 tasks run without error; problems start with the Set_fact variables and Print tcpdump relevant information tasks (errors above respectively). I also get the same second error above in the resultant phpipam_tcpdump.yaml.
I am running Ubuntu 20.04 in WSL2 in Windows 10 21.04, GNU bash, version 5.0.17(1).
---
- name: Set default_mac
set_fact:
default_mac: "{{ ansible_facts.default_ipv4.macaddress }}"
- name: Set default_interface
set_fact:
default_interface: "{{ ansible_facts.default_ipv4.interface }}"
- name: Run tcpdump on default network interface
command: tcpdump -nn -v -i "{{ default_interface }}" -s 1500 -c 1 'ether[20:2] == 0x2000'
register: tcpdump
- name: Set_fact variables
set_fact:
tcpdump_switch: "{{ tcpdump.stdout_lines | regex_search('10.[0-9]+.[0-9]+.[0-9]+') }}"
tcpdump_port: "{{ tcpdump.stdout_lines | regex_search('GigabitEthernet+[0-9]+/[0-9]+/[0-9]+') }}"
tcpdump_vlan: "{{ tcpdump.stdout_lines | regex_search('bytes: [0-9]+') | regex_replace('bytes: ') }}"
- name: Print tcpdump relevant information
no_log: false
debug:
msg:
- "MAC: {{ default_mac }}"
- "Nework interface: {{ default_interface }}"
- "Switch IP: {{ tcpdump_switch }}"
- "Port: {{ tcpdump_port }}"
- "Vlan: {{ tcpdump_vlan }}"
- name: Include phpipam_tcpdump.yaml
include: ./phpipam_tcpdump.yaml

How to use Ansible to label the nodes of K8S

At present, I can only get the host name of the host node by going to the corresponding node to store the file locally, and then I send the stored file to the master node and set the file as a registered variable to set the corresponding node label for k8s, but for more The configuration of each node is difficult. Is there any good way to achieve it?
gather_facts: yes
become: yes
tags: gets
tasks:
- name: install the latest version of rsync
yum:
name: rsync
state: latest
- name: Ansible gets the current hostname
debug: var=hostvars[inventory_hostname]['ansible_hostname']
register: result
- local_action:
module: copy
content: "{{ result }}"
dest: /tmp/Current_hostname.yml
- debug: msg="{{ item }}"
with_lines: cat /tmp/Current_hostname.yml |tr -s ' '|cut -d '"' -f6 |sort -o /tmp/Modified_hostname
- hosts: "{{ hosts | default('k8s-master') }}"
gather_facts: no
become: yes
tags: gets
tasks:
- name: install the latest version of rsync
yum:
name: rsync
state: latest
- name: Transfer file from ServerA to ServerB
synchronize:
src: /tmp/Modified_hostname
dest: /tmp/Modified_hostname
mode: pull
delegate_to: "{{ item }}"
with_items: "{{ groups['mysql'][0] }}"
- hosts: "{{ hosts | default('k8s-master') }}"
gather_facts: no
tags: gets
become: yes
vars:
k8s_mariadb: "{{ lookup('file', '/tmp/Modified_hostname') }}"
tasks:
- name: Gets the node host information
debug: msg="the value of is {{ k8s_mariadb }}"
- name: Tag MySQL fixed node
shell: kubectl label node {{ k8s_mariadb }} harbor-master1=mariadb
ignore_errors: yes

Ansible - default to everything when no arguments are specified

I have a fairly large playbook that is capable of updating up to 10 services on a given host.
Let's say I have the services a b c d and I'd like to be to be able to selectively update the services by passing command line arguments, but default to updating everything when no arguments are passed. How could you do this in Ansible without being able to drop into arbitrary scripting?
Right now what I have is a when check on each service and define whether or not the service is true at playbook invocation. Given I may have as many as 10 services, I can't write boolean logic to accommodate every possibility.
I was hoping there is maybe a builtin like $# in bash that lists all arguments and I can do a check along the lines of when: $#.length = 0
ansible-playbook deploy.yml -e "a=true b=true d=true"
when: a == "true"
when: b == "true"
when: c == "true"
when: d == "true"
I would suggest to use tags. Lets say we have two services for example nginx and fpm. Then tag the play for nginx with nginx and for fpm with fpm. Below is an example for task level tagging, let say its named play.yml
- name: tasks for nginx
service: name=nginx state=reloaded
tags:
- nginx
- name: tasks for php-fpm
service: name=php-fpm state=reloaded
tags:
- fpm
Exeucting ansible-playbook play.yml will by default run both the tasks. But, If i change the command to
ansible-playbook play.yml --tags "nginx"
then only the task with nginx tag is executed. Tags can also be applied over play level or role level.
Play level tagging would look like
- hosts: all
remote_user: user
tasks:
- include: play1.yml
tags:
- play1
- include: play2.yml
tags:
- play2
In this case, all tasks inside the playbook play1.yml will inherit the tag play1 and the same for play2. While running ansible-playbook with the tag play1 then all tasks inside play1.yml are executed. Rather if we dont specify any tag all tasks from play1 and play2 are executed.
Note: A tasks is not limited to just one tag.
If you have a single play that you want to loop over the services, define that list in group_vars/all or somewhere else that makes sense:
services:
- first
- second
- third
- fourth
Then your tasks in start_services.yml playbook can look like this:
- name: Ensure passed variables are in services list
fail:
msg: "{{ item }} not in services list"
when: item not in services
with_items: "{{ varlist | default(services) }}"
- name: Start services
service:
name: "{{ item }}"
state: started
with_items: "{{ varlist | default(services) }}"
Pass in varlist as a JSON array:
$ ansible-playbook start_services.yml --extra-vars='{"varlist":[first,third]}'

Force Ansible to gather facts from group

I want to force Ansible to gather facts about hosts inside playbook (to use those data inside role) regardless --limit, but don't know how.
I have playbook like this:
- hosts: postgres_access
tasks:
- name: Gathering info
action: setup
- hosts: postgres
roles:
- postgres
Inside 'postgres' role I have template which iterates over default IPs:
{% for host in groups['postgres_access'] %}
host all all {{hostvars[host].ansible_default_ipv4.address}}/32 md5
{% endfor %}
This works like magic, but only if I run my playbook without --limit. If I use --limit it breaks, because some hosts in hostgroup have no gathered facts.
ansible-playbook -i testing db.yml --limit postgres
failed: [pgtest] (item=pg_hba.conf) => {"failed": true, "item": "pg_hba.conf", "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'ansible_default_ipv4'"}
How can I have --limit to reconfigure only postgres host, and have network data from other hosts (without doing all other configuration stuff?).
Try this please !
- hosts: postgres
pre_tasks:
- setup:
delegate_to: "{{item}}"
with_items: "{{groups['postgres_access']}}"
roles:
- postgres
You can run setup for the hosts in the postgres_access group as a task and save the facts using register:
- name: setup hosts
action: "setup {{ item }} filter=ansible_default_ipv4"
with_items: groups.postgres_access
register: ip_v4
- name: create template
template: src=[your template] dest=[your dest file]
Just keep in mind that the template needs to change how you are referencing the hosts ipv4 address, I tried with something like this:
{% for item in ip_v4.results %}
host all all {{ item.ansible_facts.ansible_default_ipv4.address }}/32 md5
{% endfor %}
For printing just the IP of each host in the group
Try this:
- hosts: postgres
pre_tasks:
- setup:
delegate_to: postgres_access
roles:
- postgres
Use the same role which you have defined as it is with ignore_errors: true . So that for hosts which do not have gathered data will not fail.
And if you want data to be gathered for all the hosts in both groups postgres_access and postgres, then add gather_facts: true to get facts for postgres group and for postgres_access you already have a task written.
- hosts: postgres_access
tasks:
- name: Gathering info
action: setup
- hosts: postgres
gather_facts: true
roles:
- postgres
ignore_errors: true

Ansible copy module with {{ item }}

I have a yml file for variables which goes like this.
- newHosts
- hostIP: 192.168.1.22
filename: file1
- hostIP: 192.168.1.23
filename: file2
I am using add_host: {{ item.hostIP }} with_items {{ newHosts }}.
I want to copy respective file to respective hosts with something like {{ item.filename }} but it copies all files to each host. How I just copy only the corresponding file to the node. How can I do that?
You can use conditionals that are applied at each iteration of the loop for example:
- hosts: all
tasks:
- name: copy file to appropriate server
copy: src={{item.filename}} dest=/var/foo/{{item.filename}}
with_items: newHosts
when: item.hostIP == ansible_ssh_host