In my playbook i have tasks that use the hostname of a server and extrapolate data to set location and environment based on that. But some servers have unique names and I'm not sure how to set variables on those. I'd prefer not to use ansible facts since i would like to share the playbook with a team. One way I was thinking is to do what's listed below but i'm running into issues. Could someone please guide me.
Create vars_file inventory
---
customservers
customhostname1:
env: test
location: hawaii
customhostname2:
env: prod
location: alaska
In Playbook.
---
task
tasks:
- name: set hostname
shell: echo "customhostname1"
register: my_hostname
- name: setting env var
set_fact:
env: "{{ item.value.env }}"
when: my_hostname == "{{ item.key }}"
with_dict: "{{ customservers }}"
- name: outputing env var
debug:
msg: the output is {{ env }}
Expected output should be test.
Thank you.
In my playbook i have tasks that use the hostname of a server and
extrapolate data to set location and environment based on that.
Bad Idea.
But some servers have unique names and I'm not sure how to set variables on those
And that is why.
The second Bad Idea is to have TEST and PROD in the same inventory. That's just begging for a disaster. They should be two completely separate inventories, though perhaps under the same parent directory:
inventories/
inventories/test/
inventories/test/hosts
inventories/test/host_vars/
inventories/test/host_vars/customhostname1.yml
inventories/prod/
inventories/prod/hosts
inventories/prod/host_vars/
inventories/prod/host_vars/customhostname2.yml
So inventories/prod/hosts could look like this (I prefer the ini format):
[customservers]
customhostname2 location=hawaii
Or:
[customservers]
customhostname2
[customhostname2:vars]
location=hawaii
But in any case, DO NOT combine test and prod inventories.
If you still need that env variable, you can either put it in group_vars/all.yml or right in the hosts file like so:
[all:vars]
env=prod
Related
I have the following inventory file
[vm_group]
xyz001.hq.company.com
xyz002.hq.company.com
[vm_group:vars]
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_port=5986
ansible_winrm_server_cert_validation=ignore
I have a environment variable called CLIENT_LIST
echo $CLIENT_LIST
xyz001.hq.company.com,xyz002.hq.company.com
How can I do something like this
[vm_group]
${CLIENT_LIST}
so that the inventory group can be set dynamically.
I tried doing it the way I have shown above but it is not picking up the environment variable values.
Do you have any other recommendation for dynamic list. Environment variable would be my first preference though.
There are two answers to your question: multiple plays, or a dynamic inventory plugin; there is no such thing as variable substitution in the static inventory files
For the multiple-plays version, one would use add_host::
- hosts: localhost
connection: local
tasks:
- add_host:
name: '{{ item }}'
groups:
- vm_group
with_items: '{{ lookup("env", "CLIENT_LIST").split(",") }}'
- hosts: vm_group
# and you're of to the races
For the dynamic inventory version, the world is your oyster: https://docs.ansible.com/ansible/2.9/plugins/inventory.html#plugin-list
my playbook structure looks like:
- hosts: all
name: all
roles:
- roles1
- roles2
In tasks of roles1, I define such a variable
---
# tasks for roles1
- name: Get the zookeeper image tag # rel3.0
run_once: true
shell: echo '{{item.split(":")[-1]}}' # Here can get the string rel3.0 normally
with_items: "{{ret.stdout.split('\n')}}"
when: "'zookeeper' in item"
register: zk_tag
ret.stdout:
Loaded image: test/old/kafka:latest
Loaded image: test/new/mysql:v5.7
Loaded image: test/old/zookeeper:rel3.0
In tasks of roles2, I want to use the zk_tag variable
- name: Test if the variable zk_tag can be used in roles2
debug: var={{ zk_tag.stdout }}
Error :
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'
I think I encountered the following 2 problems:
When registering a variable with register, when condition is added, this variable cannot be used in all groups. How to solve this problem? How to make this variable available to all groups?
is my title, How to use variables between different roles in ansible?
You're most likely starting a new playbook for a new host. Meaning all previous collected vars are lost.
What you can do is pass a var to another host with the add_host module.
- name: Pass variable from this play to the other host in the same play
add_host:
name: hostname2
var_in_play_2: "{{ var_in_play_1 }}"
--- EDIT ---
It's a bit unclear. Why do you use the when statement in the first place if you want every host in the play for it to be available?
You might want to use the group_vars/all.yml file to place vars in.
Also, using add_host should be the way to go as how I read it. Can you post your playbook, and the outcome of your playbook on a site, e.g. pastebin?
If there is any chance the var is not defined because of a when condition, you should use a default value to force the var to be defined when using it. While you are at it, use the debug module for your tests rather than echoing something in a shell
- name: Debug my var
debug:
msg: "{{ docker_exists | default(false) }}"
I have a playbook that will iterate over a set of hosts in different environments, "dev", and "prod". The environment that a host is in will change the other variables that it has. For example, this is in my vars/main.yml file:
---
folder_list_DEV: ["folder-1", "folder-2", "folder-3"]
folder_list_PROD: ["folder-1", "folder-2"]
The intention in my example is to create a series of folders on the target system, depending on which environment it is in. The code that I would like to work, but does not, looks like this:
- name: Create folders
file:
path: "/{{ item }}"
state: present
with_items: "{{ folder_list_env }}
"env" is set on execution of the playbook (-e "env=DEV").
How can I reference this "folder_list_*" variable based on value of the "env" variable?
"{{ vars['folder_list_' + env] }}"
How can I declare global variable within Ansible playbook. I have searched in google and found the below solution, but its not working as expected.
- hosts: all
vars:
prod-servers:
- x.x.x.x
- x.x.x.x
- hosts: "{{prod-servers}}"
tasks:
- name: ping
action: ping
When I'm trying the above code, it says variable prod-servers is undefined.
You cannot define a variable accessible on a playbook level (global variable) from within a play.
Variable Scopes
Ansible has 3 main scopes:
Global: this is set by config, environment variables and the command line
Play: each play and contained structures, vars entries (vars; vars_files; vars_prompt), role defaults and vars.
Host: variables directly associated to a host, like inventory, include_vars, facts or registered task outputs
Anything you declare inside a play can thus only be either a play variable, or a (host) fact.
To define a variable, which you can use in the hosts declaration:
run ansible-playbook with --extra-vars option and pass the value in the argument;
or to achieve the same functionality (decide which hosts to run a play on, from within a preceding play):
define an in-memory inventory and run the subsequent play against that inventory.
what you seem to want is an inventory (http://docs.ansible.com/ansible/latest/intro_inventory.html), it looks like you have an static list of IP's that may be prod servers (or dev, or whatever), therefore you can create an static inventory.
In your second play you want to use the list of IP's as hosts to run the tasks, that's not what Ansible expects. After the "hosts" keyword in a play declaration, Ansible expects a group name from the inventory.
If, on the opossite, your prod servers change from time to time, you may need to create a dynamic inventory. You can have a look at examples in https://github.com/ansible/ansible/tree/devel/contrib/inventory (for instance, there are examples of dynamic inventory based on EC2 from Amazon or vsphere)
regards
well, this can be done using
set_fact.
I don't know the best practice for this but this works for me
Here's my playbook example
- hosts: all
gather_facts: false
tasks:
- set_fact: host='hostname'
- hosts: host-name1
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"
- hosts: host-name2
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"
We wanted to have a single playbook for all the deployments and the multiple hosts will be looped in. Ansible calls will be made from Jenkins pipeline by passing in the environments, for example dev6 and dev8
env1=dev6
env2=dev8
Pipeline Call:
ansible-playbook -i hosts --limit $env1:$env2 deploy_test.yml -e "env1={{$env1}} env2={{$env2}}"
I defined all the host specific variables (dev1,dev2......PERF8 etc.) in single file so it is easy to manage and maintain,
dev6:
- { deploy_domain: "Dev6Domain",
WL_Admin: "DEV6WLAdmin",
WL_Managed: "DEV6Managed" }
dev7:
- { deploy_domain: "Dev7Domain",
WL_Admin: "Dev7WLAdmin",
WL_Managed: "Dev7Managed" }
Playbook "Deploy_test.yml"
- hosts: all
vars_files:
- host_variables.yml
tasks:
- debug: msg='Target Domain is "{{ item[0].deploy_domain }}"'
with_nested:
- "{{ env1 }}"
- "{{ env2 }}"
The env1 and env2 values are being read from jenkins, no issues there
Problem-1: When the playbook runs on dev6 first, it takes dev8 values as well since it is defined under with_nested items.
Problem-2: How do I register the values specific to every environment?
for example, down the playbook when I say, mkdir /tmp/{{deploy_domain}, I need seperate values for dev6 and dev8.
Here is an example how you can read name-specific variable for every host:
hosts:
[dev6]
box1
[dev8]
box2
host_variables.yml:
dev6:
deploy_domain: "Dev6Domain"
WL_Admin: "DEV6WLAdmin"
WL_Managed: "DEV6Managed"
dev8:
deploy_domain: "Dev8Domain"
WL_Admin: "Dev8WLAdmin"
WL_Managed: "Dev8Managed"
I stripped out list level from original host_variables.yml, because it is not necessary in this case, there is always single element in the list.
deploy_test.yml:
- hosts: all
tasks:
- include_vars: host_variables.yml
- set_fact:
my_env: "{{ hostvars[inventory_hostname][group_names[0]] }}"
- debug: msg="My domain = {{ my_env.deploy_domain }}"
execution: ansible-playbook -i hosts --limit $env1:$env2 deploy_test.yml
This will execute deploy_test.yml for all hosts in groups set in env vars env1 and env2.
In the begining of playbook, we load everything from host_variables.yml as host facts.
And with set_fact extract variable named after current host's group name as my_env.
So box1 will have dev6 as my_env and box2 will have dev8.