Ansible variables passed via command line are not getting defined in the playbook.
I'm looking to pass external variables via command line to an ansible playbook. It is not working as expected using the -e, which is to call external variables based on the ansible documentation.
ansible-playbook /opt/playbooks/shutdown.yaml -f 10 -i /opt/inventory/hosts -e 'logPath=/my/log/path logName=shutdown.log logDir=shutdown'
---
- name: Transfer and execute a script.
hosts: all
remote_user: ansible
sudo: yes
tasks:
- name: Transfer the script
copy: src=/opt/files/shutdown.sh dest=/tmp/ mode=0777
- name: Execute the script
command: sh /tmp/shutdown.sh logPath logName logDir
- name: cat log output
command: cat logDir
register: myoutput
- name: get stout of execution of script
debug: msg={{ myoutput.stdout_lines }}
Here is my output, I'm expecting LogPath to be defined as the variable using key:value pair
: FAILED! => {"changed": true, "cmd": ["cat", "logPath"], "delta": "0:00:00.005258", "end": "2019-02-06 13:30:03.551631", "failed": true, "rc": 1, "start": "2019-02-06 13:30:03.546373", "stderr": "cat: logPath: No such file or directory", "stderr_lines": ["cat: logPath: No such file or directory"], "stdout": "", "stdout_lines": []}
to retry, use: --limit #/opt/playbooks/shutdown.retry
your command task seems wrong, you need to use curly brackets for ansible to treat the enclosed string as variable (and replace it with its value). Try this syntax:
- name: Execute the script
command: sh /tmp/shutdown.sh {{ logPath }} {{ logName }} {{ logDir }}
hope it helps
these should be passed in JSON notation, which would support passing other data-types than string:
-e '{"log_path":"/my/log/path","log_name":"shutdown.log","log_dir":"shutdown"}'
and then substitute accordingly:
- name: Execute the script
command: sh /tmp/shutdown.sh log_path log_name log_dir
snake-case is rather the default for variable names, than camel-case.
see the documentation.
Related
Inside my Ansible role i'd like to create an export variable which can be used by another script later in the task. But the export is not working for some reason, what am I missing?
- name: export php1_release
shell: export php1_release=8.0
- name: Echo my_env_var again
shell: echo $php1_release
register: php
- debug: var=php
I see the following output:
ok: [example.com] => {
"php": {
"changed": true,
"cmd": "echo $php1_release",
"delta": "0:00:00.003415",
"end": "2022-10-14 20:43:48.084293",
"failed": false,
"msg": "",
"rc": 0,
"start": "2022-10-14 20:43:48.080878",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
Setting an environment only affects the current process and any subprocesses that it spawns. Each shell task in your playbook starts a new, unrelated shell process, so environment variables set in one won't be visible in another (this isn't an Ansible issue; that's just how environment variables work).
You can set the variables with Ansible instead. Here, we set the variables at the play level so they will be visible in all tasks:
- hosts: somehost
environment:
php1_release: "8.0"
tasks:
- name: Echo my_env_var again
shell: echo $php1_release
register: php
- debug:
var: php.stdout
Which will output:
TASK [debug] ********************************************************************************************
ok: [localhost] => {
"php.stdout": "8.0"
}
You can also set environment variables per task:
- hosts: localhost
tasks:
- name: Echo my_env_var again
shell: echo $php1_release
register: php
environment:
php1_release: "8.0"
- debug:
var: php.stdout
This will produce the same output, but the environment variable is only visible in the Echo my_env_var again task.
I need to set the environment in the target machine. The environment variables are present in the file called .env. There are several variables inside that file like
export AB_HOME=/tl/dev/abinit/abinit-V3 #/gcc3p32 # for 32-bit
export PATH=${AB_HOME}/bin:${PATH}
I have tried the below playbook to set the environment and register the environment variables in order to use them in the environment keyword
- hosts: dev
gather_facts: false
tasks:
- name: set the environment
shell: 'su <user_id> & . ./.env'
args:
chdir: /path for the file
register: output1
- debug: var=output1
But I am not able to find the exported environment variables in the register variable.
"changed": true,
"cmd": ". ./.env",
"delta": "0:00:00.049610",
"end": "2020-02-18 09:22:16.912490",
"failed": false,
"rc": 0,
"start": "2020-02-18 09:22:16.862880",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": [],
I have tried cat the file and I am able to find the variables list but I don't know how to use that in playbook. The file also contains # at starting and also after some variables like below.
export AB_HOME=/tl/dev/abinit/abinit-V3 #/gcc3p32 # for 32-bit
My intention with below playbook is to run a shell command only when it finds any of the value from disk_list. I need help to frame out when condition as told above.
---
- hosts: localhost
connection: local
gather_facts: false
tasks:
- set_fact:
disk_list:
- sda
- sdb
- sdc
- name: Get df -hT output to know XFS file system
shell: df -hT |grep xfs|awk '{print $1}'
register: df_result
- name: Run shell command on each XFS file system
shell: ls -l {{ item }} | awk '{print $1}'
with_items: "{{ df_result.stdout_lines }}"
when: "{{ disk_list.[] }} in {{ item }}"
BTW, in my system, "df_result" variable looks as below:
TASK [debug] ***************************************************************************************************************************************
ok: [localhost] => {
"df_result": {
"changed": true,
"cmd": "df -hT |grep xfs|awk '{print $1}'",
"delta": "0:00:00.017588",
"end": "2019-03-01 23:55:21.318871",
"failed": false,
"rc": 0,
"start": "2019-03-01 23:55:21.301283",
"stderr": "",
"stderr_lines": [],
"stdout": "/dev/sda3\n/dev/sda1",
"stdout_lines": [
"/dev/sda3",
"/dev/sda1"
]
}
}
Please help !
Some notes on the playbook.
For localhost, connection: local is implicit. So there is no technical need to specify this.
set_fact is correct, but in this case I believe is more appropiate to use "vars" at a play level instead of the set_fact module in a task. This also allows you to use "vars_files" for easier use of disk device lists.
I would reccomend to try to keep your task names "easy", as you may want to use the --start-at-task option at some point.
with_items is depricated in favor of "loop".
The conditional "when" works at a task level. So it will execute the task (for all its items) if the condition is met.
Here is a working version of what you need which also reflects the (5) recommendations made:
---
- hosts: localhost
gather_facts: false
vars:
disk_list:
- sda
- sdb
- sdc
tasks:
- name: cleans previous runs
shell: cat /dev/null > /tmp/df_result
- name: creates temporary file
shell: df -hT | grep ext4 | grep -i {{ item }} | awk '{print $1}' >> /tmp/df_result
loop: "{{ disk_list }}"
- name: creates variable
shell: cat /tmp/df_result
register: df_result
- name: shows info
shell: ls -l {{ item }} | awk '{print $1}'
loop: "{{ df_result.stdout_lines }}"
I basically just use a temporary file (/tmp/df_result) with the results you need already filtered by the "grep -i {{ item }}" used in the loop on task "creates temporary file". Then, the loop in "shows info" just iterates over an already clean list of items.
To see the result on screen, you could use "-v" option when running the playbook or if you want to save the result in a file, you could add " >> /tmp/df_final" at the end of the shell line in "shows info" task.
I accidently step on this post, which is kind of old. I'm sure you already fixed this in your environment, maybe you find a better way to do it, hopefully you did.
Regards,
I am using Ansible 2.4.
I can't get following ansible-playbook to run:
test.yml
---
- hosts: "localhost"
become: no
vars:
foo_withsinglequote: !vault |
$ANSIBLE_VAULT;1.1;AES256
39313737636336313832376165636465346162366333663137373165363662316263336166393666
3566643732663063386333303638633962363863306463610a643931396636613361353165653265
38376630313939626637623538613432373336646663636563623062636238313731326263336263
3138643931323662620a336534383964663562353162393930613965386465616630363335326138
3431
foo_withdoublequote: !vault |
$ANSIBLE_VAULT;1.1;AES256
64633863363838326664323238313866616161313937323563636430326432393638336334303336
3533653339663438356238613937336466623834666537630a646139643033653237353262616662
30643732313861373130633036346361663130326332303932616433643761633739306137333237
6263653365386132620a633738663336313532366637613533313361646339623137393461383363
3332
tasks:
- name: Echo foo_withsinglequote
command: echo "{{ foo_withsinglequote }}"
- name: Echo foo_withdoublequote
command: echo "{{ foo_withdoublequote }}"
To generate the vault variables I used following:
$ echo 123 > vlt.txt
$ ansible-vault --vault-password-file=vlt.txt encrypt_string "abc\"def"
$ ansible-vault --vault-password-file=vlt.txt encrypt_string "abc\'def"
To run the playbook:
$ ansible-playbook --vault-password-file=vlt.txt test.yml
This gives following error:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ValueError: No closing quotation
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "module_stderr": "Traceback (most recent call last):\n File \"/tmp/ansible_8uz23O/ansible_module_command.py\", line 213, in \n main()\n File \"/tmp/ansible_8uz23O/ansible_module_command.py\", line 182, in main\n args = shlex.split(args)\n File \"/usr/lib/python2.7/shlex.py\", line 279, in split\n return list(lex)\n File \"/usr/lib/python2.7/shlex.py\", line 269, in next\n token = self.get_token()\n File \"/usr/lib/python2.7/shlex.py\", line 96, in get_token\n raw = self.read_token()\n File \"/usr/lib/python2.7/shlex.py\", line 172, in read_token\n raise ValueError, \"No closing quotation\"\nValueError: No closing quotation\n", "module_stdout": "", "msg": "MODULE FAILURE", "rc": 0}
How can I quote the vaulted variables correctly? Because I don't know in advance, if the vaulted variables will contain single or double quotes.
Your problem description, despite being well written, unfortunately wrongly attributes the problem to Ansible Vault.
In fact, the problem you reported, comes simply from trying to execute the task which effectively becomes:
- command: echo abc"def
Ansible Vault plays no role in causing this problem -- if you defined the variable directly with foo: abc\"def you'd get the same error message.
The solution is simply to quote the string in the echo command:
- command: echo '{{ foo }}'
Other than that you can use quote filter, but for Vault-protected variable you need to first set a static fact:
- set_fact:
bar: "{{ foo }}"
- command: echo {{ bar|quote }}
Finally, the simplest solution to the underlying problem is: do not use special characters in passwords. Increase the length instead.
I am trying to one simple task which is find out the difference between the two files and store it in notepad. I am not able to do it with command as well as shell. Please suggest where i am going wrong-
---
- hosts: myserver
tasks:
- name: get the difference
command: diff hosts.new hosts.mod
register: diff
- debug: var=diff.cmd
Error -
fatal: [zlp12037]: FAILED! => {"changed": true, "cmd": ["diff", "hosts.new", "hosts.mod"], "delta": "0:00:00.003102", "end": "2017-03-29 10:17:34.448063", "failed": true, "rc": 1, "start": "2017-03-29 10:17:34.444961", "stderr": "", "stdout":
I'm not quite sure what your input play looks like with your formatting. But the following should be a solution:
- name: "Get difference from two files"
command: diff filea fileb
args:
chdir: "/home/user/"
failed_when: "diff.rc > 1"
register: diff
- name: debug output
debug: msg="{{ diff.stdout }}"
Some explanation:
If something fails with the diff command, the return code is > 1. We evaluate this by the "failed_when".
To get the output of the command, we print the ".stdout" element.
To make sure we're in the folder where the files are, we use "chdir".
I would move the hosts.new or hosts.mod to the ansible control machine.
Run the copy module with the src as hosts.new and the dest as hosts.mod with --check and --diff. I find this method most useful to spot differences in files across a large enterprise.
Run:
ansible all -m copy -a "src=hosts.new dest=/tmp/hosts.mod" --check --diff -i hosts
Output:
--- before: /tmp/hosts.mod
+++ after: /home/ansible/hosts.new
## -1,5 +1,5 ##
host1
+host2
host3
host4
-host6
-host99
+host5
test10 | SUCCESS => {
"changed": true,
"failed": false
}