lets say I have a playbook:
---
- name
host: testserver
become_method = sudo
become_user = root
tasks:
- name: copystuff
module: copy
do stuff
- name: copy stuff
delegate_to: localhost
module: copy
do stuff
I have same user with the same password on both localhost and the testserver. But on testserver, I have to use sudo to beocme a root but on localhost I have to use dzdo to become a root.
So I was wondering if there is a way for me use either one, if one method does not work?
Yes, that's what hostvars are designed to do: declare vars per host.
You can do that in your inventory file, as shown in the fine manual, if you have an inventory file (or in most dynamic inventory sources). Or, if you are running with a more ad-hoc inventory list (such as -i machine1,localhost,machine99) then you can use a conditional set_fact: to declare that hostvar after ansible has started running:
- set_fact:
ansible_become_method: dzdo
when: inventory_hostname == "localhost"
so long as you do that before using a task that has become: yes on it
The pre_tasks: keyword may interest you, too
Related
I am trying to add a host in Ansible to the Azure dynamic inventory at run time.
First I log the "before add_host" contents of the 'ansible_play_hosts_all' inventory variable
Then I use "add_host" to add a new host
When I log the "after add_host" contents of the 'ansible_play_hosts_all' inventory variable, I can see my new host added to the list.
But when the next task in the playbook is run, it is not run on the newly added host.
I have also tried using "meta: refresh_inventory", but to no avail.
Any help is appreciated - thanks
- name: "Log the contents of the 'ansible_play_hosts_all' magic inventory variable before testing ssh connectivity"
debug:
msg: "{{ ansible_play_hosts_all }}"
# Wait for vm_to_be_added to become contactable via ssh, then refresh the inventory
- name: Waits for SSH port 22 of the EPMP host to become available
wait_for:
host: vm_to_be_added
port: 22
state: started
timeout: 600
# Add vm_to_be_added host to the dynamic inventory
- name: Add vm_to_be_addedhost to the dynamic inventory
add_host:
hostname: "vm_to_be_added"
group: tag_workspace_cluster
# Log the contents of the 'ansible_play_hosts_all' magic inventory variable after testing ssh connectivity
- name: "Log the contents of the 'ansible_play_hosts_all' magic inventory variable after testing ssh connectivity"
debug:
msg: "{{ ansible_play_hosts_all }}"
# Record the IP of the machine currently running(hosting) Ansible.
- set_fact: ANSIBLE_HOST_IP="{{lookup("pipe","hostname -I")}}"
The solution I have ended up with is:
I removed add_host and used meta: refresh_inventory (after I had waited for a connection & confirmed I could shh to the new server )
After the refresh I then started a new play. This is important, as it is only in the new play I see the new host now added to the dynamic inventory group.
In short it now looks like this:
- name: Play 1
hosts: localhost
become: true
pre_tasks:
- name: Waits for SSH port 22 of the host to become available
wait_for:
host: vm_to_be_added
port: 22
state: started
timeout: 600
# Now that we know that the vm_to_be_added is contactable, refresh to have it included in the inventory.
# The newly refreshed inventory will only be availble to the next play.
- meta: refresh_inventory
- name: Play 2
hosts: dynamic_group
become: true
pre_tasks:
# This task will be run against the newly added host
- set_fact: ANSIBLE_HOST_IP="{{lookup("pipe","hostname -I")}}"
Need to handle YUM package installation deployement process with different versions/packages, for target environments(dev/prod/systest) using ansible playbook.
NOTE: I have gone through groups_var and hosts_var concept but did not understand if multiple packages with different versions can handled for deployment in multiple environment based on input
As you found out, this separation can be achieved by using group_vars and host_vars. These are loaded in relation to the path of inventory file.
Simple example tasks like below will install different versions in dev and prod environments as explained below.
Example playbook1.yml:
- hosts: appservers
tasks:
- name: install app-a
yum:
name: 'app-a-{{ app_a_version }}'
- name: install app-b
yum:
name: 'app-b-{{ app_b_version }}'
Consider the example directory structure separating each environment's inventory:
dev/hosts
prod/hosts
systest/hosts
Each inventory file will contain hosts/groups for that environment.
Dev environment:
Example dev/hosts:
[appservers]
appserver1.dev
appserver2.dev
Then we can have variables specific to this environments in dev/group_vars/appservers.yml:
---
app_a_version: 1.1
app_b_version: 5.5
Will install app-a-1.1 and app-b-5.5 when run as:
ansible-playbook playbook1.yml -i dev/hosts
Prod environment:
Example prod/hosts:
[appservers]
appserver1.prod
appserver2.prod
And variables defined in prod/group_vars/appservers.yml:
app_a_version: 1.0
app_b_version: 5.0
But in prod it will install app-a-1.0 and app-b-5.0 when run as:
ansible-playbook playbook1.yml -i prod/hosts
host_vars work in similar way, and can be used to provide variables specific to each host of the inventory rather than groups in inventory.
I wanted to deploy multiple VMS from my ansible-playbook, so I used split function and I am getting the error of dict does not have user_inout error. Please have a look at my code.
Code:
- name: os system
pause:
prompt: |
Which os do you want to use?
1- Windows Server
2- CentOS_7
3- CentOs_8
4- Ubuntu
5- Others
register: os_system
- set_fact:
o_name: "{{ os_system.user_input.split(',') }}"
- name: Domain Decision
pause:
prompt: Do you want your PC in Domain
register: decision
when: 'item|string == "1"'
with_items:
- "{{ o_name }}"
- set_fact:
dec: "{{ decision.user_input.split(',') }}"
Now my real issue, if the user chooses option 1,2 then it will be split by set_fact for os_system and according to that input it will decide for the domain decision my main issue is that while the task is at set_fact for the decision, it will give me the error like this:
Error:
fatal: [x.x.x.x]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'user_input'\n\nThe error appears to be in '/home/x.x.x.x/sites/playbook.yml': line 82, column 6, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - set_fact:\n ^ here\n"
}
IF I remove the loop from task domain decision, then set_fact works very perfectly.
When you want to collect user input, it can be in two ways:
Interactive (prompted), using vars_prompt.
Through variables (non-prompted). For example, you could have users create a file with variables and load with vars_file.
I would prefer the second approach if possible.
However, to get user input interactively through prompts:
- hosts: my_hosts
vars_prompt:
- name: os_system
prompt: |
Which os do you want to use?
1- Windows Server
2- CentOS_7
3- CentOs_8
4- Ubuntu
5- Others
private: no
tasks:
- set_fact:
o_name: "{{ os_system.split(',') }}"
You should note that by splitting the input of 1,2 - you will not get OS name. You will again have to set a fact based on the number (1 = Windows Server). IMHO this is unnecessary complication.
A much better option would be to have users create a variables file like below:
my_vars.yml:
os_choices:
- { name: Windows Server, domain: yes }
- { name: CentOS_7, domain: no }
And load it in play using:
- hosts: my_hosts
vars_file:
- my_vars.yml
New to Ansible I'm experimenting with setting up a website under IIS.
I can create and configure an application pool, but I'm struggling with the website. The basic site works, HTTPS/SSL is still troublesome, but I read there are some bugs in the win_iis_website/win_iis_webbinding scripts that are being worked on. The part I'm stuck with are IIS' features per site.
In IIS (in the GUI) there are sub-features that can be configured for a site:
I was unable to find how to configure these using Ansible (more specifically Ansible's win_iis_website module).
I'm looking to configure ASP, Handler mappings, URL rewrites and Default documents.
Is there any way to do so?
My current yml for creating the site looks like this:
- name: create new website {{ websitename}}
win_iis_website:
name: "{{ websitename}}"
state: started
port: 443
ip: *
ssl: true
hostname: "{{ websitename }}"
application_pool: "{{ websitename }}"
physical_path: c:\inetpub\wwwroot\{{ websitename }}
parameters: logfile.directory:c:\inetpub\logs\
register: website
I am currently making Playbooks for IIS and indeed to perform the configuration there is no particular module that allows you to modify the functions of the sections, I looked in some places and the information was very scarce, there are modules for applicationPool, but for this you have to use win_shell as follows
- name: Name of playbook
win_shell: |
<PowerShell command>
You can base on the CIS BENCHMARK guide of IIS.
Check the win_feature module:
- name: Install IIS Web-Server with sub features and management tools
win_feature:
name: Web-Server
state: present
restart: True
include_sub_features: True
include_management_tools: True
if you want to do in a more controlled manner, check the installed features with the command:
Get-WindowsFeature
And add like:
- name: Install IIS
win_feature:
name: "Web-Filtering,Web-Dir-Browsing,Web-Default-Doc"
state: present
restart: no
include_sub_features: no
include_management_tools: yes
I am a newbie to ansible and I am using a very simple playbook to issue sudo apt-get update and sudo apt-get upgrade on a couple of servers.
This is the playbook I am using:
---
- name: Update Servers
hosts: my-servers
become: yes
become_user: root
tasks:
- name: update packages
apt: update_cache=yes
- name: upgrade packages
apt: upgrade=dist
and this is an extract from my ~/.ansible/inventory/hosts file:
[my-servers]
san-francisco ansible_host=san-francisco ansible_ssh_user=user ansible_become_pass=<my_sudo_password_for_user_on_san-francisco>
san-diego ansible_host=san-diego ansible_ssh_user=user ansible_become_pass=<my_sudo_password_for_user_on_san-diego>
This is what I get if I launch the playbook:
$ ansible-playbook update-servers-playbook.yml
PLAY [Update Servers] **********************************************************
TASK [setup] *******************************************************************
ok: [san-francisco]
ok: [san-diego]
TASK [update packages] *********************************************************
ok: [san-francisco]
ok: [san-diego]
TASK [upgrade packages] ********************************************************
ok: [san-francisco]
ok: [san-diego]
PLAY RECAP *********************************************************************
san-francisco : ok=3 changed=0 unreachable=0 failed=0
san-diego : ok=3 changed=0 unreachable=0 failed=0
What is bothering me is the fact that I have the password for my user user stored in plaintext in my ~/.ansible/inventory/hosts file.
I have read about vaults, I have also read about the best practices for variables and vaults but I do not understand how to apply this to my very minimal use case.
I also tried to use lookups. While in general they also work in the inventory file, and I am able to do something like this:
[my-servers]
san-francisco ansible_host=san-francisco ansible_ssh_user=user ansible_become_pass="{{ lookup('env', 'ANSIBLE_BECOME_PASSWORD_SAN_FRANCISCO') }}"
where this case the password would be stored in an environment variable called ANSIBLE_BECOME_PASSWORD_SAN_FRANCISCO; there is no way to look up variables in vaults as far as I know.
So, how could I organize my file such that I would be able to lookup up my passwords from somewhere and have them safely stored?
You need to create some vaulted variable files and then either include them in your playbooks or on the command line.
If you change your inventory file to use a variable for the become pass this variable can be vaulted:
[my-servers]
san-francisco ansible_host=san-francisco ansible_ssh_user=user ansible_become_pass='{{ sanfrancisco_become_pass }}'
san-diego ansible_host=san-diego ansible_ssh_user=user ansible_become_pass='{{ sandiego_become_pass }}'
Then use ansible-vault create vaulted_vars.yml to create a vaulted file with the following contents:
sanfrancisco_become_pass: <my_sudo_password_for_user_on_san-francisco>
sandiego_become_pass : <my_sudo_password_for_user_on_san-diego>
Then either include the vaulted file as extra vars like this:
ansible-playbook -i ~/.ansible/inventory/hosts playbook.yml --ask-vault-pass -e#~/.ansible/inventory/vault_vars
Or include the vars file in your playbook with an include_vars task:
- name : include vaulted variables
include_vars: ~/.ansible/inventory/vault_vars
The best way to solve this problem is to use host_vars. The easiest setup is to just put the ansible_become_pass in Vault encrypted files in the corresponding host_vars directories like this:
myplaybook.yml
host_vars/onehost.com/crypted
host_vars/otherhost.com/crypted
In the crypted files you place the assignment of the ansible_become_pass variable:
ansible_become_pass: SuperSecre3t
Create the file with ansible-vault create, edit it with ansible-vault edit.
Following the advice in the Ansible docs you need to create an additional file per host that assigns the ansible_become_passwd from the crypted variable that has a different name. That way it is possible to search for the ansible_become_passwd in the project files.
myplaybook.yml
host_vars/onehost.com/plain
host_vars/onehost.com/crypted
host_vars/otherhost.com/plain
host_vars/otherhost.com/crypted
where a plain file contains something like this:
ansible_become_pass: "{{ vaulted_become_pass }}"
and the crypted file sets the vaulted_become_pass like shown above.
All crypted files must be encrypted with the same key and ansible-playbook must be called with --ask-vault-pass.
After setting up an inventory with your own relevant settings. These settings assume that you have already set up a rsa-key pair to access your server. You should be able to ssh into your server with ssh remoteuser#155.42.88.199
[local]
localhost ansible_connection=local
[remote]
155.42.88.199 ansible_connection=ssh ansible_user=remoteuser ansible_become_user=root ansible_become=yes ansible_ssh_private_key_file=<private_key_file_path>
You need to store your root password in a file (I called mine 'my_vault.yml'). You can do this with the following command:
~/.ansible$ ansible-vault create my_vault.yml
Simple store your remote server password as follows (do not include the '<>' tags)
su_password: <myreallyspecialpassword>
The password will now be encrypted by vault and the only way to view this is to enter the following command.
~/.ansible$ ansible-vault edit my_vault.yml
We now need to include our 'my_vault.yml' file in our playbook. We can do this by using vars-files to get the value of su-password. We can now create a var titled ansible_become_pass which will be passed the value from our my_vault.yml file which will allow our remoteuser to su once on the server.
---
- name: My Awesome Playbook
hosts: remote
become: yes
vars_files:
- ~/.ansible/my_vault.yml
vars:
ansible_become_pass: '{{ su_password }}'
roles:
- some_awesome_role
As we are using vault each time we want to run this playbook we need to use the following command.
ansible-playbook myawesome_playbook.yml --ask-vault-pass