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.
Related
I am trying to load variables from a YAML file to be used as environment variables in a later task of the same playbook. This is what I am doing:
Template host vars in YAML format:
- name: builtin | template | template host variables file
ansible.builtin.template:
src: templates/django/hostvars.j2
dest: "host_vars/{{ inventory_hostname_short }}.yml"
mode: 0640
output_encoding: "utf-8"
delegate_to: localhost
This is producing the following file:
--
# Host variables to be set as environment variables in tasks that need it
POSTGRES_PASSWORD: "<password>"
POSTGRES_USER: "dbuser"
POSTGRES_DB: "dbname"
POSTGRES_HOST: "dbhost"
POSTGRES_PORT: 5432
POSTGRES_SSLMODE: "verify-full"
POSTGRES_SSLCA: "/etc/ssl/certs/ISRG_Root_X1.pem"
POSTGRES_APPNAME: "myproject"
DJANGO_SITE_NAME: "mysite"
DJANGO_SITE_PASSWORD: "mypassword"
DJANGO_SITE_USER: "myuser"
DJANGO_SITE_ID: 2
DJANGO_SECRET_KEY: "<very-long-and-random-secret>"
[..]
Use include_vars to load the vars into the playbook:
- name: builtin | include_vars | load host vars
ansible.builtin.include_vars:
file: "host_vars/{{ inventory_hostname_short }}.yml"
name: envvars
Later on the playbook, check that the variables are there:
- name: builtin | debug | print variable 'envvars'
ansible.builtin.debug:
var: envvars
This is working as intended (apparently) and a list of KEY: value variables is being printed, such as:
TASK [builtin | debug | print variable 'envvars'] ***************************************************************
ok: [django1.mydomain.com] => {
"envvars": {
"DJANGO_DEBUG": 0,
"DJANGO_LOGS_DIR": "/opt/django/logs",
"DJANGO_MEDIA_BASE": "/opt/django/media",
"DJANGO_SECRET_KEY": "<very-long-and-random-secret>",
[..]
Use django_manage to update the database schema:
- name: community.general | django_manage | update database schema
community.general.django_manage:
command: migrate
settings: myproject.settings
project_path: "/opt/django/src"
virtualenv: "/opt/django/venv"
become: true
become_user: django
become_method: su
environment: "{{ envvars }}"
This, unfortunately, is failing. Django is complaining that it cannot find the SECRET_KEY environment variable, which it should build based on one of the variables in the abovementioned list (especifically, DJANGO_SECRET_KEY).
Incidentally, if I run the following task, nothing is printed out:
- name: print environment variables
ansible.builtin.command: env
become: true
become_user: django
become_method: su
environment: "{{ envvars }}"
And I don't understand why. I've tried to debug using -vvv and they are being sent by Ansible though the SSH connection (at least so it seems).
Any hints on what bit I am doing wrong?
EDIT 1
I've changed the tasks list file where I use django_manage into the following code:
- name: builtin | shell | capture DJANGO_ environment variables
debugger: on_failed
ansible.builtin.shell:
cmd: "env | grep DJANGO_"
register: out
environment: "{{ envvars }}"
become: true
become_user: django
become_method: su
- name: builtin | debug | pinrt content of out.stdout
ansible.builtin.debug:
var: out.stdout
- name: builtin | debug | print variable 'envvars'
ansible.builtin.debug:
var: envvars
- name: community.general | django_manage | populate the static subdirectory
community.general.django_manage:
command: collectstatic
clear: yes
project_path: "/opt/django/src"
virtualenv: "/opt/django/venv"
become: true
become_user: django
become_method: su
environment: "{{ envvars }}"
The second and third tasks both print the values of the variables (the first one from the env | grep DJANGO_ command sent via shell and the second is the value of the envvars variable which is being sent via the environment: directive.
This is the error of the last task:
TASK [builtin | shell | capture DJANGO_ environment variables] *************************************************************************************************************
changed: [django1.donmain.com]
TASK [builtin | debug | pinrt content of out.stdout] ***********************************************************************************************************************
ok: [django1.django.com] => {
"out.stdout": "DJANGO_SITE_USER=mysite\nDJANGO_MEDIA_BASE=/opt/django/media\nDJANGO_SITE_NAME=mysite\nDJANGO_SITE_ID=2\nDJANGO_SECRET_KEY=<very-secret-key>\nDJANGO_LOGS_DIR=/opt/django/logs\nDJANGO_SETTINGS_MODULE=myproject.settings.production\nDJANGO_DEBUG=0\nDJANGO_STATIC_BASE=/opt/django/static\nDJANGO_SITE_PASSWORD=mypassword\nDJANGO_SITE_VERSION=57a2f3c168d86243f03809e5d02a0f50a8fa892e"
}
TASK [builtin | debug | print variable 'envvars'] **************************************************************************************************************************
ok: [django1.domain.com] => {
"envvars": {
"DJANGO_DEBUG": 0,
"DJANGO_LOGS_DIR": "/opt/django/logs",
"DJANGO_MEDIA_BASE": "/opt/django/media",
"DJANGO_SECRET_KEY": "<very-secret-key>",
"DJANGO_SETTINGS_MODULE": "myproject.settings.production",
"DJANGO_SITE_ID": 2,
"DJANGO_SITE_NAME": "mysite",
"DJANGO_SITE_PASSWORD": "mypassword",
"DJANGO_SITE_USER": "myuser",
[..]
}
}
TASK [community.general | django_manage | populate the static subdirectory] ************************************************************************************************
fatal: [django1.domain.com]: FAILED! => {"changed": false, "cmd": ["./manage.py", "collectstatic", "--noinput", "--clear"], "msg": "\n:stderr: Traceback (most recent call last):\n File \"/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py\", line 204, in fetch_command\n app_name = commands[subcommand]\nKeyError: 'collectstatic'\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/opt/django/src/./manage.py\", line 22, in <module>\n execute_from_command_line(sys.argv)\n File \"/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py\", line 381, in execute_from_command_line\n utility.execute()\n File \"/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py\", line 375, in execute\n self.fetch_command(subcommand).run_from_argv(self.argv)\n File \"/opt/django/venv/lib/python3.9/site-packages/django/core/management/__init__.py\", line 211, in fetch_command\n settings.INSTALLED_APPS\n File \"/opt/django/venv/lib/python3.9/site-packages/django/conf/__init__.py\", line 57, in __getattr__\n self._setup(name)\n File \"/opt/django/venv/lib/python3.9/site-packages/django/conf/__init__.py\", line 44, in _setup\n self._wrapped = Settings(settings_module)\n File \"/opt/django/venv/lib/python3.9/site-packages/django/conf/__init__.py\", line 107, in __init__\n mod = importlib.import_module(self.SETTINGS_MODULE)\n File \"/usr/lib/python3.9/importlib/__init__.py\", line 127, in import_module\n return _bootstrap._gcd_import(name[level:], package, level)\n File \"<frozen importlib._bootstrap>\", line 1030, in _gcd_import\n File \"<frozen importlib._bootstrap>\", line 1007, in _find_and_load\n File \"<frozen importlib._bootstrap>\", line 986, in _find_and_load_unlocked\n File \"<frozen importlib._bootstrap>\", line 680, in _load_unlocked\n File \"<frozen importlib._bootstrap_external>\", line 790, in exec_module\n File \"<frozen importlib._bootstrap>\", line 228, in _call_with_frames_removed\n File \"/opt/django/src/black_pearl/settings/production.py\", line 3, in <module>\n from black_pearl.settings.common import *\n File \"/opt/django/src/black_pearl/settings/common.py\", line 301, in <module>\n path_app = import_module(app).__path__\n File \"/usr/lib/python3.9/importlib/__init__.py\", line 127, in import_module\n return _bootstrap._gcd_import(name[level:], package, level)\nModuleNotFoundError: No module named 'None'\n", "path": "/opt/django/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "syspath": ["/tmp/ansible_community.general.django_manage_payload_l53eeo4g/ansible_community.general.django_manage_payload.zip", "/usr/lib/python39.zip", "/usr/lib/python3.9", "/usr/lib/python3.9/lib-dynload", "/usr/local/lib/python3.9/dist-packages", "/usr/lib/python3/dist-packages"]}
PLAY RECAP *****************************************************************************************************************************************************************
django1.domain.com : ok=14 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Thanks in advance.
Q: "Nothing is printed out."
A: Register the output if you want to see it. For example
- hosts: localhost
tasks:
- command: echo $DJANGO_DEBUG
register: out
environment:
DJANGO_DEBUG: 0
- debug:
var: out.stdout
gives (abridged)
out.stdout: '0'
This should work for you. Step by step add the complexity to your code and isolate the problem. For example, the playbook below should display the environment at the remote host
- hosts: test_11
vars:
env:
DJANGO_DEBUG: 0
DJANGO_SITE_NAME: mysite
DJANGO_SITE_PASSWORD: mypassword
DJANGO_SITE_USER: myuser
DJANGO_SITE_ID: 2
tasks:
- shell: env | grep DJANGO_
register: out
environment: "{{ env }}"
- debug:
var: out.stdout
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.
I'm trying to use Ansible to hit a bunch (100+) Cisco Catalyst switches and check if they have a certain line card installed. Via SSH, this can be done with the "sh mod" command. I want to parse the output of that command in a playbook and then show the output of the command if a certain string matches. Right now with the playbook below I get the following error:
fatal: [redacted-hostname]: FAILED! => {"failed": true, "msg": "The
conditional check 'showmod | search(\"4548\")' failed. The error was:
Unexpected templating type error occurred on ({% if showmod |
search(\"4548\") %} True {% else %} False {% endif %}): expected
string or buffer\n\nThe error appears to have been in
'/etc/ansible/playbooks/linecard-4548.yaml': line 22, column 5, but
may\nbe elsewhere in the file depending on the exact syntax
problem.\n\nThe offending line appears to be:\n\n\n - debug:
\"msg='4548 Card Found'\"\n ^ here\n"}
Current playbook code:
---
- hosts: redacted-hostname
gather_facts: yes
connection: local
tasks:
- name: SYS | Define provider
set_fact:
provider:
host: "{{ inventory_hostname }}"
username: redacted-user
password: redacted-password
- name: IOS | Get Module List
ios_command:
provider: "{{ provider }}"
commands:
- sh mod | inc 4548
register: showmod
- debug: "msg='4548 Card Found'"
when: showmod.stdout | search("/4548/")
I've tried the when in the debug with and without the .stdout to no avail. I've done some research and the error I'm getting usually occurs when, in my case, showmod is undefined but it definitely is. If I replace the debug with the following snippet, the playbook runs fine but of course it'll print the output for every switch which isn't what I want.
- name: IOS | Show Output
debug:
var: showmod
Any suggestions?
ios_command returns stdout as list and stdout_lines as list of lists (whereas command module return stdout as string and stdout_lines as list).
So in your case, you may want to try:
- debug: "msg='4548 Card Found'"
when: showmod.stdout | join(" ") | search("/4548/")
I want to use Hashicorp Vault with Ansible to retrieve username/password which I will use in Ansible playbook.
Vault is setup - I created a secret. What are the steps to integrate both? the documentation around plugins isn't that great. I tried the file lookup from ansible and this works but how to use 3rd party plugins? Can somebody help me with the steps to follow?
Install the plugin, pip install ansible-modules-hashivault
What is the difference with https://github.com/jhaals/ansible-vault
2.a The environment variables (VAULT ADDR & VAULT TOKEN) I put where?
Change ansible.cfg to point to vault.py which is located in "plugin" folder of my Ansible Project
To test basic integration, can I use the following playbook?
https://pypi.python.org/pypi/ansible-modules-hashivault
- hosts: localhost
-tasks:
- hashivault_status:
register: 'vault_status'
Tried this but I get:
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 119, in run
res = self._execute()
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 431, in _execute
self._task.post_validate(templar=templar)
File "/usr/lib/python2.7/site-packages/ansible/playbook/task.py", line 248, in post_validate
super(Task, self).post_validate(templar)
File "/usr/lib/python2.7/site-packages/ansible/playbook/base.py", line 371, in post_validate
value = templar.template(getattr(self, name))
File "/usr/lib/python2.7/site-packages/ansible/template/__init__.py", line 359, in template
d[k] = self.template(variable[k], preserve_trailing_newlines=preserve_trailing_newlines, fail_on_undefined=fail_on_undefined, overrides=overrides)
File "/usr/lib/python2.7/site-packages/ansible/template/__init__.py", line 331, in template
result = self._do_template(variable, preserve_trailing_newlines=preserve_trailing_newlines, escape_backslashes=escape_backslashes, fail_on_undefined=fail_on_undefined, overrides=overrides)
File "/usr/lib/python2.7/site-packages/ansible/template/__init__.py", line 507, in _do_template
res = j2_concat(rf)
File "<template>", line 8, in root
File "/usr/lib/python2.7/site-packages/jinja2/runtime.py", line 193, in call
return __obj(*args, **kwargs)
File "/usr/lib/python2.7/site-packages/ansible/template/__init__.py", line 420, in _lookup
instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self)
File "/usr/lib/python2.7/site-packages/ansible/plugins/__init__.py", line 339, in get
self._module_cache[path] = self._load_module_source('.'.join([self.package, name]), path)
File "/usr/lib/python2.7/site-packages/ansible/plugins/__init__.py", line 324, in _load_module_source
module = imp.load_source(name, path, module_file)
File "/etc/ansible/ProjectA/lookup_plugins/vault.py", line 5
<!DOCTYPE html>
^
SyntaxError: invalid syntax
fatal: [win01]: FAILED! => {
"failed": true,
"msg": "Unexpected failure during module execution.",
"stdout": ""
Since you put so many eggs into the post, that I have no clue what the question is really about, here's something to get you going with the native lookup plugin and jhaals/ansible-vault.
you can create lookup_plugins in the current directory and save vault.py inside;
the VAULT_ADDR and VAULT_TOKEN environment variables are as you see them in the script;
The Bash script below (it uses screen and jq, you might need to install them) runs Vault in dev mode, sets the secret, and runs Ansible playbook which queries the secret with two lookup plugins:
#!/bin/bash
set -euo pipefail
export VAULT_ADDR=http://127.0.0.1:8200
if [[ ! $(pgrep -f "vault server -dev") ]]; then
echo \"vault server -dev\" not running, starting...
screen -S vault -d -m vault server -dev
printf "sleeping for 3 seconds\n"
sleep 3
else
echo \"vault server -dev\" already running, leaving as is...
fi
vault write secret/hello value=world excited=yes
export VAULT_TOKEN=$(vault token-create -format=json | jq -r .auth.client_token)
ansible-playbook playbook.yml --extra-vars="vault_token=${VAULT_TOKEN}"
and playbook.yml:
---
- hosts: localhost
connection: local
tasks:
- name: Retrieve secret/hello using native hashi_vault plugin
debug: msg="{{ lookup('hashi_vault', 'secret=secret/hello token={{ vault_token }} url=http://127.0.0.1:8200') }}"
- name: Retrieve secret/hello using jhaals vault lookup
debug: msg="{{ lookup('vault', 'secret/hello') }}"
In the end you should get:
TASK [Retrieve secret/hello using native hashi_vault plugin] *******************
ok: [localhost] => {
"msg": "world"
}
TASK [Retrieve secret/hello using jhaals vault lookup] *************************
ok: [localhost] => {
"msg": {
"excited": "yes",
"value": "world"
}
}
The word world was fetched from Vault.
When I have this role:
# playbooks/roles/ansible/tasks/main.yml
- name: Install Ansible
pip:
state: present
name: ansible
version: "{{ ansible_version }}"
# playbooks/roles/ansible/defaults/main.yml
ansible_version: 1.9.4
I get this error while running ansible-playbook version 1.9.4 or 2.0.0.2:
TASK: [ansible | Install Ansible] *********************************************
failed: [localhost] => {"cmd": "/usr/local/bin/pip install ansible=={'major': 1, 'full': '1.9.4', 'string': '1.9.4\\n configured module search path = None', 'minor': 9, 'revision': 4}", "failed": true}
msg:
:stderr: Invalid requirement: 'ansible=={major:'
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/pip/req/req_install.py", line 73, in __init__
req = pkg_resources.Requirement.parse(req)
File "/usr/local/lib/python2.7/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 3036, in parse
req, = parse_requirements(s)
File "/usr/local/lib/python2.7/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 2980, in parse_requirements
"version spec")
File "/usr/local/lib/python2.7/dist-packages/pip/_vendor/pkg_resources/__init__.py", line 2945, in scan_list
raise RequirementParseError(msg, line, "at", line[p:])
RequirementParseError: Expected version spec in ansible=={major: at =={major:
This is the playbook:
- name: Install Sensu
serial: "100%"
hosts: all
sudo: yes
roles:
- role: "ansible-pull"
server_type: "sensu"
ansible_version: "2"
Where the ansible-pull role depends on the ansible role in meta/main.yml.
Am I injecting the variable incorrectly in this case? Is there some problem with setting the variable in the dependent ansible-pull roll rather than directly in the ansible role?
It turns out that ansible_version is a magic variable set by Ansible.
Who knew?
Using an arbitrarily different but unused variable name does the trick.