Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm attempting to create a conditional in my playbook that switches based on an ENV defined in a Dockerfile. The playbook is copied in by the Dockerfile, and Ansible runs it against localhost to do some configuration. However, these playbooks are also used to configure an ordinary server.
Here's my question: Is is possible to use a conditional when defining hosts?
- hosts: actual_server
roles:
- some_roles
when:
- DOCKER_CONTAINER is not defined
- hosts: docker_container
roles:
- almost_same_roles
when:
- DOCKER_CONTAINER is true
I've hunted through the Ansible docs, and found several examples where multiple hosts are targeted in a single playbook, but I an unsure if my syntax for the conditional is wrong, or if what I want to accomplish simply cannot be done. Am I limited to defining conditionals only on a role-by-role basis?
I'd be glad to edit this question, to make it more clear, since it has been closed for being "unclear"... but I'm not sure how much MORE clear I could be, than stating exactly what I'm asking in the above. Glad for more specific feedback if anyone is willing to give it.
It honestly feels like this behavior should be pushed lower into the tasks as opposed to the role level. Roles describe how to accomplish a specific state through a list of tasks, and the tasks themselves perform the steps in order to accomplish that specific state.
With that said, it makes sense to have the logic in the task to determine whether or not it will execute. This means that your role some_roles would look like this (warning: untested).
# In tasks/playbook.yml
- hosts: actual_server
roles:
- some_roles
vars:
environment_type: Server
- hosts: docker_container
roles:
- some_roles
vars:
environment_type: Docker
# In vars/main.yml file
environment_type: Server
# In tasks/main.yml
- name: Download a tarball
get_url:
url: "https://example.com/some_package.tar.gz"
dest: /tmp
mode: 0750
when: environment_type == 'Docker'
If you want to run one ansible script for the different environment.
Here is your answer, you can go with inventory file for each environment generated by docker(if needed).
ansible-playbook playbook.yml -i development.ini
ansible-playbook playbook.yml -i testing.ini
ansible-playbook playbook.yml -i staging.ini
development.ini
[actual_server]
192.168.0.100 # some IP address
[docker_container]
127.0.0.1
testing.ini
[actual_server]
192.168.0.101 # some IP address
[docker_container]
127.0.0.1
https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
https://symfonycasts.com/screencast/ansible/hosts-inventory
Not the ideal answer, but you can use a when condition on each role:
- hosts: actual_server
roles:
- role: role1
when: DOCKER_CONTAINER is not defined
- role: role2
when: DOCKER_CONTAINER is not defined
...
- hosts: docker_container
roles:
- role: role3
when: DOCKER_CONTAINER is true
- role: role4
when: DOCKER_CONTAINER is true
...
Related
I used to store ansible_ssh_pass in host_vars, enctypted with ansible-vault, but now i want to move it to hashicorp-vault. I wrote a simple role to get this variable from hashicorp-vault and set it as ansible_ssh_pass, so i can connect to host via it. But unless i do it i can't gather facts, so the only way is to set gather_facts: no and run
- name: Gathering facts
setup:
at the end of my role. But now i need to change my playbooks and some roles for this. Is there a better way to run role before gathering facts or force Ansible to get variable from hashicorp-vault?
It sounds like you should be using the hashi_vault lookup plugin.
For example, you could set in your inventory something like this:
all:
vars:
ansible_ssh_pass: "{{ lookup('hashi_vault', 'secret=secret/ssh_password:value' }}
hosts:
host1:
host2:
...
This would require you to have VAULT_ADDR and VAULT_TOKEN set appropriately in your environment.
NB: I don't have a Vault instance to play with, but I do something very similar using the aws_secret lookup.
I'm trying to create a playbook that will first modify another playbook, then run that modified version of the playbook. But import_playbook pre-processes, so the original playbook, not the modified, is run. Is there any way to tell Ansible to re-read this playbook? Note I am changing more that the hosts, but using this simple example.
- name: Change the playbook
hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Change the playbook
lineinfile:
path: "my_playbook.yml"
regexp: "- hosts: some_group_name"
line: "- hosts: some_other_group_name"
- name: Include the playbook that was modified
import_playbook: my_playbook.yml
With proper organized inventory, group_vars, variables, templating and add_host or dynamic inventory, there is no need for self-modifying code (SMC).
Regarding
But import_playbook pre-processes, so the original playbook ...
you may have a look into What's the difference between include_tasks and import_tasks?.
Furthermore, there is no dynamic include_playbook.
I want to parameterize (use a variable) for remote_user in ansible.
This is the first part from the playbook:
- hosts: xxx
remote_user: "centos"
become: true
I will replace it with
- hosts: wazuh
remote_user: "{{ new_user }}"
become: true
But what is a good place to store the value of this variable? It seems group_vars/all mostly contain variables which are more app/env specific than ansible specific. Or should I put it in inventories/hosts as a var? What is the recommended location to store it?
You should actually store it in your inventory as ansible_user either for the all group (for all host), a specific group or a specific host. You can keep a remote_user in your play which will be used in case the ansible_user is not defined for some hosts in your inventory. If you remove it, you local user on the controller will be the default, unless you use the -u flag on the command line.
You can find a good explanation of the difference between ansible_user and remote_user and how the overide works in the documentation on variable precedence
Using a var as you wrote it in your above example can actually work. But since it must be expanded before the play actually starts and any action is taken on any host, the only place you can "store" it is in an extra_var on the command line.
To be a little more practical, here is what I suggest from your above example:
inventories/dev/hosts.yml
---
wazuh:
hosts:
host_a.wazuh.tld:
host.b.wazuh.tld:
inventories/dev/group_vars/wazuh.yml
---
# Vars for the wazuh group
ansible_user: centos
plabook.yml
---
- hosts: wazuh
tasks:
- name: Proove we connected with the given user
cmd: whoami
register: whoami_result
- name: Show actual result
debug:
var: whoami_result.stdout
Launching the playbook:
ansible-playbook -i inventories/dev playbook.yml
I have a playbook with this structure:
---
- hosts: foo-servers
roles:
- foo_setup
become: yes
tags: tweaks
- hosts: bar-servers
roles:
- bar_setup
become: yes
tags: tweaks
[a few more server groups with a similar pattern]
I have a somewhat similar feature to deploy in all servers but each server group has it's own small differences, so I need to keep separate roles for each group.
I also want to run just a select group of tasks from each role, the ones tagged 'tweaks', in all hosts.
And all hosts should be run with raised privileges, but that is not true for all playbooks, so I want that setting to apply just to this playbook (no global vars).
I would like to move all the repeated parameters - become: yes and tags: tweaks outside of host: plays where they will be indicated to apply to all roles bellow. Something to the effect of
--
- all_hosts_this_playbook:
become: yes
tags: tweaks
- hosts: foo-servers
roles:
- foo_setup
- hosts: bar-servers
roles:
- bar_setup
I suppose this is possible in the command line. Like ansible-playbook setup_tweaks.yml --tags "tweak" --become? But is there a playbook equivalent? I'd rather have these in the file than in the command line, where I often forget to add stuff.
And looping doesn't work...
ERROR! 'loop' is not a valid attribute for a Play
- name: Make tweaks in many servers
become: yes
tags: tweaks
hosts: "{{ item.host }}"
roles:
- "{{ item.role }}"
loop:
- { host: 'foo-servers', role: 'foo_setup' }
- { host: 'bar-servers', role: 'bar_setup' }
I also want to add post_tasks: to be run in all servers (maybe they also need to be tagged?):
post_tasks_all_hosts:
- name: Upgrade system
apt:
autoremove: yes
autoclean: yes
update_cache: yes
upgrade: dist
tags: tweaks
- name: Reboot
shell: sleep 2 && reboot
async: 3
poll: 0
tags: tweaks
Is it possible to define playbook-wide pre_tasks or post_tasks?
Here Ansible: How to declare global variable within playbook? it is indicated that one 'cannot define a variable accessible on a playbook level', but in my case it's not variables - it's task parameters and post_tasks:.
Maybe the parameters and the 'pre/post tasks' are different problems with different solutions, but I decided to ask in the same place because they both fall on the same category of parameters that I'd like to set for the whole playbook, outside of host: plays.
Q: "I suppose this is possible in the command line. Like ansible-playbook setup_tweaks.yml --tags "tweak" --become? But is there a playbook equivalent?"
A: No. There is no such playbook equivalent.
Isn't this is a misunderstanding of the command-line option --tags
only run plays and tasks tagged with these values
versus
tag inheritance ?
Adding tags: to a play, or to statically imported tasks and roles, adds those tags to all of the contained tasks...When you apply tags: attributes to structures other than tasks, Ansible processes the tag attribute to apply ONLY to the tasks they contain. Applying tags anywhere other than tasks is just a convenience so you don’t have to tag tasks individually.
Details
In the play below tag "tweaks" is added to all of the contained tasks
- hosts: foo-servers
roles:
- foo_setup
tags: tweaks
The command below selects only tasks tagged "tweaks"
ansible-playbook setup_tweaks.yml --tags "tweak"
Q: "Is it possible to define playbook-wide pre_tasks or post_tasks?"
A: No. It's not possible. The scope of pre/post_tasks is the play.
I am writing a master Ansible playbook which is including playbooks. Now, I want to set variables that all the playbooks specified within it use. How do I specify variables in this playbook?
I know that one of the options is to include vars_files and use it with each of the playbook. Example: - include: abc.yml
vars_files: vars.yml
I am using Ansible 1.9.3.
First I would really recommend you to update your Ansible to latest version. It is very easy to do so, no reason to stay behind.
Having said that, there are many ways on how to specify variables in your master playbook. All these are more or less the same with any other playbook. Briefly mentioning:
a. Define them in your playbook itself
- hosts: webservers
vars:
http_port: 80
b. Separating into a variable file, as you already said:
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
vars/external_vars.yml
somevar: somevalue
password: magic
Other possibilities include:
c. Using facts
d. Registering output into variables
Additionally, which may be important for your case:
d. You can pass variables into includes:
tasks:
- include: wordpress.yml wp_user=timmy
- include: wordpress.yml wp_user=alice
- include: wordpress.yml wp_user=bob
e. Passing variables in command line:
ansible-playbook release.yml -k "version=1.23.45 other_variable=foo"
-k is shorthand for --exra-vars.
There might be other ways too that I may be missing at the moment.