I am trying to access the contents of a variable, from a variable name. I've used ansible vault to create some passwords, and I am trying to create database users, like so:
postgresql_user:
name: "{{ item }}"
db: "{{ item }}"
login_user: postgres_admin
login_password: '{{postgres_admin}}'
login_host: localhost
login_port: 5433
password: '{{ "{{item}}" }}'
loop:
- artifactory
- bitbucket
- confluence
- crowd
- jira
In this case, I have a database user, which is the variable in the loop. The password for that user, is stored inside the (vault) variable name of that user. In the password: field like I am trying to do a double reference. It doesn't work.
I've tried a few more things, but this is my first run with Ansible and I don't want to go down the wrong path. (I did not include the reference to the vault but it's at the top of the file, and it has been tested with a simpler tasks)
Thanks!
Use lookup plugin vars. For example
password: "{{ lookup('vars', item) }}"
With the introduction of the collections the documentation of the plugins is not available online anymore. See the documentation from the command-line
shell> ansible-doc -t lookup vars
To make the code both more robust and user-friendly, I'd propose to rename the variables with the passwords. For example "artifactory_passwd" etc. Then, in the lookup, create the name of the variable dynamically
password: "{{ lookup('vars', item ~ '_passwd') }}"
Related
I have a file called values.txt on each of the server in the directory /tmp/values.txt and it has some values. And I have a jinja template and I am substituting some values from the the values.txt
But the problem is, when i use the lookup command it looks in the controller server and not the remote servers
Here's what I tried:
- name: Create /etc/systemd/system/etcd.service
template:
src: etcd.service.j2
dest: /etc/systemd/system/etcd.service
vars:
value_from_file: "{{ lookup('file', '/tmp/values.txt').split('\n') }}"
vars_from_jinja: [SELF_NAME, SELF_IP, NODE_1_NAME, NODE_1_IP, NODE_2_NAME, NODE_2_IP, NODE_3_NAME, NODE_3_IP, NODE_4_NAME, NODE_4_IP]
my_dict: "{{ dict(vars_from_jinja|zip(value_from_file)) }}"
How can I can this task remotely? Or is there another workaround to substitute the values to the jinja template?
PS: I can't fetch the values.txt to the controller because the content of values.txt in each server is slightly different from the other.
Can someone please help me?
The lookup find the file (or stream) on the controller. If you file is on the remote node, you can't use the lookup
Lookup plugins are an Ansible-specific extension to the Jinja2 templating language. You can use lookup plugins to access data from outside sources (files, databases, key/value stores, APIs, and other services) within your playbooks. Like all templating, lookups execute and are evaluated on the Ansible control machine. Ansible makes the data returned by a lookup plugin available using the standard templating system. You can use lookup plugins to load variables or templates with information from external sources.
try the cat file instead:
- name: read the values.txt
shell: cat /tmp/values.txt
register: data
- name: Create /etc/systemd/system/etcd.service
template:
src: etcd.service.j2
dest: /etc/systemd/system/etcd.service
vars:
value_from_file: "{{ data.stdout_lines }}"
vars_from_jinja: [ SELF_NAME, SELF_IP, NODE_1_NAME, NODE_1_IP, NODE_2_NAME, NODE_2_IP, NODE_3_NAME, NODE_3_IP, NODE_4_NAME, NODE_4_IP ]
my_dict: "{{ dict(vars_from_jinja|zip(value_from_file)) }}"
Use slurp:
- name: read remote values.txt
register: values
ansible.builtin.slurp:
src: /tmp/values.txt
- name: Create /etc/systemd/system/etcd.service
template:
src: etcd.service.j2
dest: /etc/systemd/system/etcd.service
vars:
value_from_file: "{{ (values.content | b64decode).split('\n') }}"
vars_from_jinja: [SELF_NAME, SELF_IP, NODE_1_NAME, NODE_1_IP, NODE_2_NAME, NODE_2_IP, NODE_3_NAME, NODE_3_IP, NODE_4_NAME, NODE_4_IP]
my_dict: "{{ dict(vars_from_jinja|zip(value_from_file)) }}"
I'm writing a playbook to create many user accounts across many servers. At the end I want to get output with credentials sorted by username.
I used set_fact with run_once but it seems that defined variable is not playbook-wide.
main.yml
- name: Create users
import_tasks: creation_task.yml
creation_task.yml
- name: Init variable for creds
set_fact:
creds: []
delegate_to: localhost
run_once: true
- name: Create specific users
include: create.yml
with_items:
- input_data
- .......
- name: Print output creds
debug: var=creds
run_once: true
create.yml
- name: some actions that actually create users
....
- name: add creds to list
set_fact:
creds: "{{ creds + [ {'hostname': inventory_hostname,'username':item.name,'password':password.stdout} ]}}"
- name: add splitter to list
set_fact:
creds: "{{ creds + [ '-----------------------------------------------------' ]}}"
This is actually working but i get output sorted by server because (as I think) every host reports his version of "creds" variable.
I'd like to create one variable that will be visible and writeable across all nested plays. So output would be sorted by input data but not hostname. Is it possible?
I'd use the following syntax, to fetch a variable set from a specific host via hostvars:
- debug:
msg: "{{ groups['my_host_name']|map('extract',hostvars,'my_variable_name')|list|first }}"
when: groups['my_host_name']|map('extract',hostvars,'my_variable_name')|list|first|length > 0
Then, you can loop over your hostnames to create an array of values and sort them.
Though, printing all servers hostnames, users & plain text passwords in a text file seems to be a security risk.
I want to know how I can import user account variables at multiple levels using loops/arrays and importing them all.
i.e. I have a generic module which has users defined in roles/common/tasks/main.yml as an array(or loop if more precise):
- name: add admin users on RHEL
user:
name: "{{ item.username }}"
comment: "{{ item.comment }}"
state: present
groups: wheel
shell: /bin/bash
password: "{{ item.password }}"
with_items: "{{ users }}"
when: ansible_facts["os_family"] == "RedHat"
tags: common
and the user attributes are all set as variables and the variables for these users are being picked up from roles/common/vars/main.yml
I also have user variables defined under group_vars/dev and group_vars/prd
And I also have specific users defined at host level under host_vars/server1
Now the problem is that Ansible is only picking up users from one level, whilst I want to pick up all the user variables from all levels, i.e. sysadmins, dev users & specific host users, and add them all in, not just from the most preferred variable source.
In Puppet this is achieved by using Hiera and hiera_hash which allows variable values to get collectively applied from all hiera levels.
How can the same be achieved with Ansible ?
I would like to use the zabbix _maintenance module.
But I want to send the host_groups as an extra var so I can put multiple host groups in maintenance.
The problem I faced is that the host_group needs a list of items and I can't understand how to write the role so it will run over a list given to it by the extra var
I tried :
- name: maintenance
zabbix_maintenance:
name: Pause
host_groups:
- "{{ item }}"
with_items:
- { 'zabbix_hosts_groups' }
state: "{{ zabbix_state }}"
server_url: http://zabbix.XXX.com
login_user: YYY
login_password: XXX
minutes: 90
desc: "Paused-for-dep"
and running it:
ansible-playbook -i 'localhost,' --connection=local zabbix-maintenance.yml -e '{"zabbix_hosts_groups":"Test1","Test2"}' -e 'zabbix_state=present
Syntactically correct task definition would be:
- name: maintenance
zabbix_maintenance:
name: Pause
host_groups: "{{ zabbix_hosts_groups }}"
state: "{{ zabbix_state }}"
server_url: http://zabbix.XXX.com
login_user: YYY
login_password: XXX
minutes: 90
desc: "Paused-for-dep"
I don't understand the problem description though. "Jenkins"??? "How to write the role"??? Please at least learn the vocabulary required to ask a question.
I use ansible module zabbix_host. There is an attribute link_templates. But it removes all groups which are linked to your host before.
I have not managed this yet. So now I use this to add common templates, and then handly link required templates in Zabbix GUI.
Check this repo, maybe you'll find some helpful: igogorevi4:Ansible
I'm using the ec2 module with ansible-playbook I want to set a variable to the contents of a file. Here's how I'm currently doing it.
Var with the filename
shell task to cat the file
use the result of the cat to pass to the ec2 module.
Example contents of my playbook.
vars:
amazon_linux_ami: "ami-fb8e9292"
user_data_file: "base-ami-userdata.sh"
tasks:
- name: user_data_contents
shell: cat {{ user_data_file }}
register: user_data_action
- name: launch ec2-instance
local_action:
...
user_data: "{{ user_data_action.stdout }}"
I assume there's a much easier way to do this, but I couldn't find it while searching Ansible docs.
You can use lookups in Ansible in order to get the contents of a file, e.g.
user_data: "{{ lookup('file', user_data_file) }}"
Caveat: This lookup will work with local files, not remote files.
Here's a complete example from the docs:
- hosts: all
vars:
contents: "{{ lookup('file', '/etc/foo.txt') }}"
tasks:
- debug: msg="the value of foo.txt is {{ contents }}"
You can use the slurp module to fetch a file from the remote host: (Thanks to #mlissner for suggesting it)
vars:
amazon_linux_ami: "ami-fb8e9292"
user_data_file: "base-ami-userdata.sh"
tasks:
- name: Load data
slurp:
src: "{{ user_data_file }}"
register: slurped_user_data
- name: Decode data and store as fact # You can skip this if you want to use the right hand side directly...
set_fact:
user_data: "{{ slurped_user_data.content | b64decode }}"
You can use fetch module to copy files from remote hosts to local, and lookup module to read the content of fetched files.
lookup only works on localhost. If you want to retrieve variables from a variables file you made remotely use include_vars: {{ varfile }} . Contents of {{ varfile }} should be a dictionary of the form {"key":"value"}, you will find ansible gives you trouble if you include a space after the colon.