summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToshio Kuratomi <toshio@fedoraproject.org>2015-03-02 12:25:41 -0800
committerToshio Kuratomi <toshio@fedoraproject.org>2015-03-02 12:25:41 -0800
commita717c89a53ee0e2c245ea83a027edb33c9e0caf5 (patch)
tree25cd00e62044fd7e7ff3e4bbde6b7bab2139117c
parenta5ac9aafada0eeb541b0d8dbc506b66cd38b504b (diff)
downloadansible-checksum-quoting2.tar.gz
Rework the shell quoting of remote checksummingchecksum-quoting2
Instead of getting rid of pipes.quote, use pipes.quote and get rid of the manually entered toplevel quotes. This should properly escape backslashes, quotes, and other characters. Also fix the new checksumming python "one-liner" for csh. ansible_shell_type needs to be set to csh. Fixes #10363 Fixes #10353
-rw-r--r--lib/ansible/runner/shell_plugins/csh.py3
-rw-r--r--lib/ansible/runner/shell_plugins/sh.py16
-rw-r--r--test/integration/check_mode.yml1
-rw-r--r--test/integration/roles/prepare_tests/tasks/main.yml2
-rw-r--r--test/integration/roles/test_check_mode/files/foo.txt1
-rw-r--r--test/integration/roles/test_check_mode/meta/main.yml3
-rw-r--r--test/integration/roles/test_check_mode/tasks/main.yml39
-rw-r--r--test/integration/roles/test_check_mode/templates/foo.j21
-rw-r--r--test/integration/roles/test_check_mode/vars/main.yml1
-rw-r--r--test/integration/roles/test_template/tasks/main.yml36
10 files changed, 99 insertions, 4 deletions
diff --git a/lib/ansible/runner/shell_plugins/csh.py b/lib/ansible/runner/shell_plugins/csh.py
index 137c013c12..4e9f8c8af7 100644
--- a/lib/ansible/runner/shell_plugins/csh.py
+++ b/lib/ansible/runner/shell_plugins/csh.py
@@ -19,5 +19,8 @@ from ansible.runner.shell_plugins.sh import ShellModule as ShModule
class ShellModule(ShModule):
+ # How to end lines in a python script one-liner
+ _SHELL_EMBEDDED_PY_EOL = '\\\n'
+
def env_prefix(self, **kwargs):
return 'env %s' % super(ShellModule, self).env_prefix(**kwargs)
diff --git a/lib/ansible/runner/shell_plugins/sh.py b/lib/ansible/runner/shell_plugins/sh.py
index fc4063c204..5fb0dc3add 100644
--- a/lib/ansible/runner/shell_plugins/sh.py
+++ b/lib/ansible/runner/shell_plugins/sh.py
@@ -24,6 +24,9 @@ _USER_HOME_PATH_RE = re.compile(r'^~[_.A-Za-z0-9][-_.A-Za-z0-9]*$')
class ShellModule(object):
+ # How to end lines in a python script one-liner
+ _SHELL_EMBEDDED_PY_EOL = '\n'
+
def env_prefix(self, **kwargs):
'''Build command prefix with environment variables.'''
env = dict(
@@ -103,14 +106,19 @@ class ShellModule(object):
# 2: No read permissions on the file
# 3: File is a directory
# 4: No python interpreter
- test = "rc=flag; [ -r \'%(p)s\' ] || rc=2; [ -f \'%(p)s\' ] || rc=1; [ -d \'%(p)s\' ] && rc=3; %(i)s -V 2>/dev/null || rc=4; [ x\"$rc\" != \"xflag\" ] && echo \"${rc}\"\' %(p)s\' && exit 0" % dict(p=path, i=python_interp)
+
+ # Quoting gets complex here. We're writing a python string that's
+ # used by a variety of shells on the remote host to invoke a python
+ # "one-liner".
+ shell_escaped_path = pipes.quote(path)
+ test = "rc=flag; [ -r %(p)s ] || rc=2; [ -f %(p)s ] || rc=1; [ -d %(p)s ] && rc=3; %(i)s -V 2>/dev/null || rc=4; [ x\"$rc\" != \"xflag\" ] && echo \"${rc} \"%(p)s && exit 0" % dict(p=shell_escaped_path, i=python_interp)
csums = [
- "(%s -c 'import hashlib; BLOCKSIZE = 65536; hasher = hashlib.sha1();\nafile = open(\"%s\", \"rb\")\nbuf = afile.read(BLOCKSIZE)\nwhile len(buf) > 0:\n\thasher.update(buf)\n\tbuf = afile.read(BLOCKSIZE)\nafile.close()\nprint(hasher.hexdigest())' 2>/dev/null)" % (python_interp, path), # Python > 2.4 (including python3)
- "(%s -c 'import sha; BLOCKSIZE = 65536; hasher = sha.sha();\nafile = open(\"%s\", \"rb\")\nbuf = afile.read(BLOCKSIZE)\nwhile len(buf) > 0:\n\thasher.update(buf)\n\tbuf = afile.read(BLOCKSIZE)\nafile.close()\nprint(hasher.hexdigest())' 2>/dev/null)" % (python_interp, path), # Python == 2.4
+ "({0} -c 'import hashlib; BLOCKSIZE = 65536; hasher = hashlib.sha1();{2}afile = open(\"'{1}'\", \"rb\"){2}buf = afile.read(BLOCKSIZE){2}while len(buf) > 0:{2}\thasher.update(buf){2}\tbuf = afile.read(BLOCKSIZE){2}afile.close(){2}print(hasher.hexdigest())' 2>/dev/null)".format(python_interp, shell_escaped_path, self._SHELL_EMBEDDED_PY_EOL), # Python > 2.4 (including python3)
+ "({0} -c 'import sha; BLOCKSIZE = 65536; hasher = sha.sha();{2}afile = open(\"'{1}'\", \"rb\"){2}buf = afile.read(BLOCKSIZE){2}while len(buf) > 0:{2}\thasher.update(buf){2}\tbuf = afile.read(BLOCKSIZE){2}afile.close(){2}print(hasher.hexdigest())' 2>/dev/null)".format(python_interp, shell_escaped_path, self._SHELL_EMBEDDED_PY_EOL), # Python == 2.4
]
cmd = " || ".join(csums)
- cmd = "%s; %s || (echo \'0 %s\')" % (test, cmd, path)
+ cmd = "%s; %s || (echo \'0 \'%s)" % (test, cmd, shell_escaped_path)
return cmd
def build_module_command(self, env_string, shebang, cmd, rm_tmp=None):
diff --git a/test/integration/check_mode.yml b/test/integration/check_mode.yml
index f2679699e0..ff04a690ec 100644
--- a/test/integration/check_mode.yml
+++ b/test/integration/check_mode.yml
@@ -1,3 +1,4 @@
- hosts: testhost
roles:
- { role: test_always_run, tags: test_always_run }
+ - { role: test_check_mode, tags: test_check_mode }
diff --git a/test/integration/roles/prepare_tests/tasks/main.yml b/test/integration/roles/prepare_tests/tasks/main.yml
index fbdb7f861c..3641880baa 100644
--- a/test/integration/roles/prepare_tests/tasks/main.yml
+++ b/test/integration/roles/prepare_tests/tasks/main.yml
@@ -19,11 +19,13 @@
- name: clean out the test directory
file: name={{output_dir|mandatory}} state=absent
+ always_run: True
tags:
- prepare
- name: create the test directory
file: name={{output_dir}} state=directory
+ always_run: True
tags:
- prepare
diff --git a/test/integration/roles/test_check_mode/files/foo.txt b/test/integration/roles/test_check_mode/files/foo.txt
new file mode 100644
index 0000000000..3e96db9b3e
--- /dev/null
+++ b/test/integration/roles/test_check_mode/files/foo.txt
@@ -0,0 +1 @@
+templated_var_loaded
diff --git a/test/integration/roles/test_check_mode/meta/main.yml b/test/integration/roles/test_check_mode/meta/main.yml
new file mode 100644
index 0000000000..1050c23ce3
--- /dev/null
+++ b/test/integration/roles/test_check_mode/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - prepare_tests
+
diff --git a/test/integration/roles/test_check_mode/tasks/main.yml b/test/integration/roles/test_check_mode/tasks/main.yml
new file mode 100644
index 0000000000..d8edf5b285
--- /dev/null
+++ b/test/integration/roles/test_check_mode/tasks/main.yml
@@ -0,0 +1,39 @@
+# test code for the template module
+# (c) 2014, Michael DeHaan <michael.dehaan@gmail.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+- name: fill in a basic template in check mode
+ template: src=foo.j2 dest={{output_dir}}/foo.templated mode=0644
+ register: template_result
+
+- name: verify that the file was marked as changed in check mode
+ assert:
+ that:
+ - "template_result.changed == true"
+
+- name: Actually create the file
+ template: src=foo.j2 dest={{output_dir}}/foo.templated2 mode=0644
+ always_run: True
+
+- name: fill in a basic template in check mode
+ template: src=foo.j2 dest={{output_dir}}/foo.templated2 mode=0644
+ register: template_result2
+
+- name: verify that the file was marked as not changed in check mode
+ assert:
+ that:
+ - "template_result2.changed == false"
diff --git a/test/integration/roles/test_check_mode/templates/foo.j2 b/test/integration/roles/test_check_mode/templates/foo.j2
new file mode 100644
index 0000000000..55aab8f1ea
--- /dev/null
+++ b/test/integration/roles/test_check_mode/templates/foo.j2
@@ -0,0 +1 @@
+{{ templated_var }}
diff --git a/test/integration/roles/test_check_mode/vars/main.yml b/test/integration/roles/test_check_mode/vars/main.yml
new file mode 100644
index 0000000000..1e8f64ccf4
--- /dev/null
+++ b/test/integration/roles/test_check_mode/vars/main.yml
@@ -0,0 +1 @@
+templated_var: templated_var_loaded
diff --git a/test/integration/roles/test_template/tasks/main.yml b/test/integration/roles/test_template/tasks/main.yml
index 8ab6d4ac19..2568843cf7 100644
--- a/test/integration/roles/test_template/tasks/main.yml
+++ b/test/integration/roles/test_template/tasks/main.yml
@@ -138,3 +138,39 @@
that:
- "template_result.changed == False"
+# Test strange filenames
+
+- name: Create a temp dir for filename tests
+ file:
+ state: directory
+ dest: '{{ output_dir }}/filename-tests'
+
+- name: create a file with an unusual filename
+ template:
+ src: foo.j2
+ dest: "{{ output_dir }}/filename-tests/foo t'e~m\\plated"
+ register: template_result
+
+- assert:
+ that:
+ - "template_result.changed == True"
+
+- name: check that the unusual filename was created
+ command: "ls {{ output_dir }}/filename-tests/"
+ register: unusual_results
+
+- assert:
+ that:
+ - "\"foo t'e~m\\plated\" in unusual_results.stdout_lines"
+ - "{{unusual_results.stdout_lines| length}} == 1"
+
+- name: check that the unusual filename can be checked for changes
+ template:
+ src: foo.j2
+ dest: "{{ output_dir }}/filename-tests/foo t'e~m\\plated"
+ register: template_result
+
+- assert:
+ that:
+ - "template_result.changed == False"
+