we want to create ansible code that ask interactive questions like the bash script
for now we have the following bash script, with diff 43 Questions , that finally create ini file according to our Questions
bash /home/gentwo.bash
how many machines?23
how many datanode services?
IP address for first machine - andnenda01?
.
.
.
---
as we know we cant do the same with ansible as the following:
- hosts: 17.12.22.56
gather_facts: yes
vars:
app_name: interactive process
ansible_user: root
ansible_password: XXXXXXXXXXX
tasks:
- name: interactive process
script: "/home/gentwo.bash"
register: results
so what is the equivalent approach with ansible?
You can use prompts for interactive input
e.g. from docs:
---
- hosts: all
vars_prompt:
- name: username
prompt: What is your username?
private: no
- name: password
prompt: What is your password?
tasks:
- name: Print a message
ansible.builtin.debug:
msg: 'Logging in as {{ username }}'
Ansible Doc: https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html
Related
i hope everyone can help me with my ansible task problem. I deploy the snmp configurations via ansible on my servers and work with snmp-extend to trigger my scripts over snmp with certain OIDs. After my playbook has run and ansible deploy the snmp configurations, i manually execute the following command to become the OID for certain extend, for example:
snmptranslate -On NET-SNMP-EXTEND-MIB::nsExtendOutput1Line.\"folder-size-/home\"
This part i would like to do automatically via ansible, i have the variables:
snmp_mountpoints_extends:
- folder-size
- folder-avail
- folder-used
and in my inventory I define for host the following variables:
server1:
custom_mountpoints:
- /home
- /opt
my ansible part:
name: Generate OIDs for custom inventroy variables
become: yes
shell: 'snmptranslate -On NET-SNMP-EXTEND-MIB::nsExtendOutput1Line.\"{{ item }}-{{ custom_mountpoints[0] }}\"'
with_items:
"{{ snmp_mountpoints_extends }}"
register: custom_mountpoints_output
when:
- custom_mountpoints is defined
- name: print output from custom_mountpoints_output
debug: msg={{ custom_mountpoints_output }}
This work fine but only for first host variable /home. How can I iterate over my custom_mountpoints with each vars from snmp_mountpoints_extends?
thank you in advance
According Ansible documentation Iterating over nested lists you may use the following approach
---
- hosts:localhost
become: false
gather_facts: false
vars:
server1:
custom_mountpoints:
- /home
- /opt
snmp_mountpoints_extends:
- folder-size
- folder-avail
- folder-used
tasks:
- name: Iterating over nested lists
debug:
msg: "{{ item[0] }} and {{ item[1] }}"
loop: "{{ server1.custom_mountpoints | product(snmp_mountpoints_extend) | list }}"
resulting into the desired output.
/home and folder-size
/home and folder-avail
/home and folder-used
/opt and folder-size
/opt and folder-avail
/opt and folder-used
Only output from the first command is written to the file.
How do I make it write output from all of the commands to the file?
---
- name: run show commands
hosts: nexus1
gather_facts: False
tasks:
- name: run show commands on nexus
nxos_command:
commands:
- show hostname
- show ip route
- show interface
- show ip interface vrf all
- show hsrp
register: output
- name: Copy to server
copy:
content: "{{ output.stdout[0] }}"
dest: "/home/CiscoOutPut/{{ inventory_hostname }}.txt"
You're only asking for output from the first command. output.stdout is a list, one item for the output of each command. When ask for output.stdout[0], you're asking for only the first result.
If you want to write the output of all commands to a file, then something like:
- name: Copy to server
copy:
content: "{{ '\n'.join(output.stdout) }}"
dest: "/home/CiscoOutPut/{{ inventory_hostname }}.txt"
I am trying to read an Environment variable from Target Linux Host using Ansible playbook. I tried all the below tasks as per the document but there is no result.
- name: Test1
debug: msg="{{ ansible_env.BULK }}"
delegate_to: "{{ target_host }}"
- name: Test2
shell: echo $BULK
delegate_to: "{{ target_host }}"
register: foo
- debug: msg="{{ foo.stdout }}"
- name: Test3
debug: msg="{{ lookup('env','BULK')}} is an environment variable"
delegate_to: "{{ target_host }}"
The Environment variable "BULK" is not set in the local Host where I am executing the playbook, so I assume its returning nothing. Instead of BULK, if I use "HOME" which is always available, it returns the result. If I SSH into the target_host I am able to run echo $BULK without any issue.
How to obtain the Environment variable from the remote host?
If I SSH into the target_host I am able to run echo $BULK without any issue.
Most likely, because BULK is set in one of the rc-files sourced only in an interactive session of the shell on the target machine. And Ansible's gather_facts task runs in a non-interactive one.
How to obtain the Environment variable from the remote host?
Move the line setting the BULK variable to a place where it is sourced regardless of the session type (where exactly, depends on the target OS and shell)
See for example: https://unix.stackexchange.com/a/170499/133107 for hints.
source /etc/profile and then grep the env
my solution is not perfect, but often works. for example i want to check if the remote_host has environment variables for proxy servers, i do the following:
as an adhoc ansible command:
ansible remote_host -b -m shell -a '. /etc/profile && (env | grep -iP "proxy")'
Explanation:
i prefere the shell module, it does what i expect... the same if i do it on a shell
. /etc/profile sources the /etc/profile. And this file sources other files like under /etc/profile.d . So after this i have the fix machine part of the environment.
env | grep -iP "proxy" then filter the expanded environment for my variables i am looking for
Remote environment variables will be automatically gathered by ansible during the "Gathering Facts" task.
You can inspect them like this:
- name: inspect env vars
debug:
var: ansible_facts.env
In your case try this:
- name: Test4
debug: msg="{{ ansible_facts.env.BULK }} is the value of an environment variable"
I am trying to change password for a non-root Linux user from Ansible playbook.
To do so I tried to follow this link
Following the instruction I can successfully change the password of a non-root user by typing the code below in the terminal.
$ echo -e "your_current_pass\nlinuxpassword\nlinuxpassword" | passwd
Changing password for testuser.
(current) UNIX password: Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully
After that I am trying to automate the code with an Ansible playbook like below,
---
- hosts: all
gather_facts: no
tasks:
- name: "Check if user exists"
register: user1_exists
raw: getent passwd {{ ansible_user }}
ignore_errors: true
- name: "Change {{ ansible_user }} password"
raw: echo -e "my_current_pass\nmy_new_pass\nmy_new_pass" | passwd
when: user1_exists|success
I am using the raw module of Ansible here as most of my machines don't have Python installed. I do not have superuser (sudo) permission either to use become: True in playbook.
Also using password based authentication here to run the Ansible playbook on target machine. Not ssh based authentication.
But while I am executing the playbook I am getting this error,
TASK [change user1 password] ***************************************************
fatal: [192.168.0.57]: FAILED! => {"changed": true, "failed": true, "rc": 10,
"stderr": "Shared connection to 192.168.0.57 closed.\r\n", "stdout": "Changing
password for testuser.\r\n(current) UNIX password: passwd: Authentication
token manipulation error\r\npasswd: password unchanged\r\n", "stdout_lines":
["Changing password for testuser.", "(current) UNIX password: passwd:
Authentication token manipulation error", "passwd: password unchanged"]}
Could anyone show me the mistakes I am making here?
Use the built-in user module instead of a shell command. This requires become: True in your playbook. Note that the password parameter of the user module requires an encrypted value. The password_hash jinja filter will help you there.
- name: change user's password
user:
name: foo
password: "{{ 'passwordsaresecret' | password_hash('sha512') }}"
Your playbook is almost correct. I had the same kind of requirement and I used your playbook. There was just one mistake in your playbook, you forgot to enclose your password variables in '{{}}' braces. So I changed your playbook like below and it worked for me.
hosts: all
gather_facts: no
tasks:
- name: "Check if user exists"
register: user1_exists
raw: getent passwd {{ ansible_user }}
ignore_errors: true
- name: "Change {{ ansible_user }} password"
raw: echo -e "{{ ansible_password }}\n{{newpwd}}\n{{newpwd}}" | passwd
when: user1_exists|success
I've hacked together the following to solve this.
The password's don't show in log or even verbose log '-vvvvv' and are not visible in history on remote systems:
---
- name: Change password when connecting as a non-root/non-sudoer user.
#
# Ansible's 'user' module can only change a password if it is ran as a root user or 'become' is used.
# For a non-root user, when you run 'passwd', it asks for current password before you can enter a new one.
# Workaround: Create a a temporary script that updates the password and run that script remoteley
# and use 'no_log' directive to prevent passwords being visible in any log.
# Tested that passwords not visible in verbose output '-vvvvv' and not in 'history' of remote computers.
# The temporary script is deleted remotley automatically by 'script' module.
# Note:
# New password must comply with your passwd security policy.
hosts: all
gather_facts: no
vars_prompt:
- name: "curr_pass"
prompt: Type in current password
private: yes
- name: "new_pass"
prompt: Type in new password
private: yes
confirm: yes
## If you need to *temporary* hard-code credentials, use below.
## Delete after use or use vault if you want long-term storage.
#vars:
#- curr_pass: MyOldPass
#- new_pass: MyNewPass123!!
tasks:
- name: Create a temporary local script which will change the users password
copy:
dest: updatePassNonRootDynamic.sh
content: echo -e '{{curr_pass}}\n{{new_pass}}\n{{new_pass}}' | passwd
delegate_to: localhost
no_log: True
run_once: true
- name: Change password via temporary script on all hosts
script: updatePassNonRootDynamic.sh
- name: Remove the temporary local script
file:
path: updatePassNonRootDynamic.sh
state: absent
delegate_to: localhost
run_once: true
I'm trying yo push my dot files and some personal configuration files to a server (I'm not root or sudoer). Ansible connects as my user in order to edit files in my home folder.
I'd like to set my default shell to usr/bin/fish.
I am not allowed to edit /etc/passwd so
user:
name: shaka
shell: /usr/bin/fish
won't run.
I also checked the chsh command but the executable prompt for my password.
How could I change my shell on such machines ? (Debian 8, Ubuntu 16, Opensuse)
I know this is old, but I wanted to post this in case anyone else comes back here looking for advise like I did:
If you're running local playbooks, you might not be specifying the user and expecting to change the shell of user you're running the playbook as.
The problem is that you can't change the shell without elevating the privileges (become: yes), but when you do - you're running things as root. Which just changes the shell of the root user. You can double check that this is the case by looking at /etc/passwd and seeing what the root shell is.
Here's my recipe for changing the shell of the user running the playbook:
- name: set up zsh for user
hosts: localhost
become: no
vars:
the_user: "{{ ansible_user_id }}"
tasks:
- name: change user shell to zsh
become: yes
user:
name: "{{ the_user }}"
shell: /bin/zsh
This will set the variable the_user to the current running user, but will change the shell of that user using root.
I ended up using two ansible modules :
ansible expect
ansible prompt
First I record my password with a prompt :
vars_prompt:
- name: "my_password"
prompt: "Enter password"
private: yes
And then I use the module expect to send the password to the chsh command :
tasks:
- name: Case insensitve password string match
expect:
command: "chsh -s /usr/bin/fish"
responses:
(?i)password: "{{ my_password }}"
creates: ".shell_is_fish"
The creates sets a lock file avoiding this task to be triggered again. This may be dangerous because the shell could be changed after and ansible will not update it (because of the lock still present). You may want to avoid this behaviour.
Here is how I do it:
- name: Set login shell of user {{ ansible_env.USER }} to `/bin/zsh` with `usermod`
ansible.builtin.command: usermod --shell /bin/zsh {{ ansible_env.USER }}
become: true
changed_when: false
Ubuntu 16
add first line in ~/.bashrc
/usr/bin/fish && exit