From e2b60475147204ff5c06de3b4f0e2106ded064ff Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Thu, 4 Oct 2018 07:02:42 -0700 Subject: [PATCH] Add symlinks sanity test. (#46467) * Add symlinks sanity test. * Replace legacy test symlinks with actual content. * Remove dir symlink from template_jinja2_latest. * Update import test to use generated library dir. * Fix copy test symlink setup. --- .../rst/dev_guide/testing/sanity/symlinks.rst | 6 + .../subdir/subdir1/ansible-test-abs-link | 1 - .../subdir/subdir1/ansible-test-abs-link-dir | 1 - .../targets/copy/files/subdir/subdir1/invalid | 1 - .../copy/files/subdir/subdir1/invalid2 | 1 - .../files/subdir/subdir1/out_of_tree_circle | 1 - .../targets/copy/files/subdir/subdir1/subdir3 | 1 - test/integration/targets/copy/tasks/main.yml | 19 ++- .../template_jinja2_latest/roles/template | 1 - .../targets/template_jinja2_latest/runme.sh | 3 + test/legacy/roles/setup_ec2 | 1 - test/legacy/roles/setup_ec2/defaults/main.yml | 2 + test/legacy/roles/setup_ec2/tasks/common.yml | 119 ++++++++++++++++++ test/legacy/roles/setup_ec2/vars/main.yml | 3 + test/legacy/roles/setup_sshkey | 1 - test/legacy/roles/setup_sshkey/tasks/main.yml | 55 ++++++++ test/runner/lib/sanity/import.py | 18 ++- test/sanity/code-smell/symlinks.json | 4 + test/sanity/code-smell/symlinks.py | 35 ++++++ test/sanity/import/lib/ansible/__init__.py | 1 - test/sanity/import/lib/ansible/module_utils | 1 - 21 files changed, 259 insertions(+), 16 deletions(-) create mode 100644 docs/docsite/rst/dev_guide/testing/sanity/symlinks.rst delete mode 120000 test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link delete mode 120000 test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link-dir delete mode 120000 test/integration/targets/copy/files/subdir/subdir1/invalid delete mode 120000 test/integration/targets/copy/files/subdir/subdir1/invalid2 delete mode 120000 test/integration/targets/copy/files/subdir/subdir1/out_of_tree_circle delete mode 120000 test/integration/targets/copy/files/subdir/subdir1/subdir3 delete mode 120000 test/integration/targets/template_jinja2_latest/roles/template delete mode 120000 test/legacy/roles/setup_ec2 create mode 100644 test/legacy/roles/setup_ec2/defaults/main.yml create mode 100644 test/legacy/roles/setup_ec2/tasks/common.yml create mode 100644 test/legacy/roles/setup_ec2/vars/main.yml delete mode 120000 test/legacy/roles/setup_sshkey create mode 100644 test/legacy/roles/setup_sshkey/tasks/main.yml create mode 100644 test/sanity/code-smell/symlinks.json create mode 100755 test/sanity/code-smell/symlinks.py delete mode 100644 test/sanity/import/lib/ansible/__init__.py delete mode 120000 test/sanity/import/lib/ansible/module_utils diff --git a/docs/docsite/rst/dev_guide/testing/sanity/symlinks.rst b/docs/docsite/rst/dev_guide/testing/sanity/symlinks.rst new file mode 100644 index 0000000000..66dbf50068 --- /dev/null +++ b/docs/docsite/rst/dev_guide/testing/sanity/symlinks.rst @@ -0,0 +1,6 @@ +Sanity Tests ยป symlinks +======================= + +Symbolic links are only permitted for files that exist to ensure proper tarball generation during a release. + +If other types of symlinks are needed for tests they must be created as part of the test. diff --git a/test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link b/test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link deleted file mode 120000 index 94491ad891..0000000000 --- a/test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link +++ /dev/null @@ -1 +0,0 @@ -/tmp/ansible-test-abs-link \ No newline at end of file diff --git a/test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link-dir b/test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link-dir deleted file mode 120000 index f5eccbbf28..0000000000 --- a/test/integration/targets/copy/files/subdir/subdir1/ansible-test-abs-link-dir +++ /dev/null @@ -1 +0,0 @@ -/tmp/ansible-test-abs-link-dir \ No newline at end of file diff --git a/test/integration/targets/copy/files/subdir/subdir1/invalid b/test/integration/targets/copy/files/subdir/subdir1/invalid deleted file mode 120000 index e466dcbd8e..0000000000 --- a/test/integration/targets/copy/files/subdir/subdir1/invalid +++ /dev/null @@ -1 +0,0 @@ -invalid \ No newline at end of file diff --git a/test/integration/targets/copy/files/subdir/subdir1/invalid2 b/test/integration/targets/copy/files/subdir/subdir1/invalid2 deleted file mode 120000 index e1b2509c07..0000000000 --- a/test/integration/targets/copy/files/subdir/subdir1/invalid2 +++ /dev/null @@ -1 +0,0 @@ -../invalid \ No newline at end of file diff --git a/test/integration/targets/copy/files/subdir/subdir1/out_of_tree_circle b/test/integration/targets/copy/files/subdir/subdir1/out_of_tree_circle deleted file mode 120000 index 218b55eabb..0000000000 --- a/test/integration/targets/copy/files/subdir/subdir1/out_of_tree_circle +++ /dev/null @@ -1 +0,0 @@ -/tmp/ansible-test-link-dir/out_of_tree_circle \ No newline at end of file diff --git a/test/integration/targets/copy/files/subdir/subdir1/subdir3 b/test/integration/targets/copy/files/subdir/subdir1/subdir3 deleted file mode 120000 index 15b47586b5..0000000000 --- a/test/integration/targets/copy/files/subdir/subdir1/subdir3 +++ /dev/null @@ -1 +0,0 @@ -../subdir2/subdir3 \ No newline at end of file diff --git a/test/integration/targets/copy/tasks/main.yml b/test/integration/targets/copy/tasks/main.yml index c5f6c03bb4..e1ae5a46b6 100644 --- a/test/integration/targets/copy/tasks/main.yml +++ b/test/integration/targets/copy/tasks/main.yml @@ -9,15 +9,25 @@ local_temp_dir: '{{ tempfile_result.stdout }}' # output_dir is hardcoded in test/runner/lib/executor.py and created there remote_dir: '{{ output_dir }}' + symlinks: + ansible-test-abs-link: /tmp/ansible-test-abs-link + ansible-test-abs-link-dir: /tmp/ansible-test-abs-link-dir + circles: ../ + invalid: invalid + invalid2: ../invalid + out_of_tree_circle: /tmp/ansible-test-link-dir/out_of_tree_circle + subdir3: ../subdir2/subdir3 - file: path={{local_temp_dir}} state=directory name: ensure temp dir exists # file cannot do this properly, use command instead - - name: Create circular symbolic link - command: ln -s ../ circles + - name: Create symbolic link + command: "ln -s '{{ item.value }}' '{{ item.key }}'" args: chdir: '{{role_path}}/files/subdir/subdir1' + warn: no + with_dict: "{{ symlinks }}" - name: Create remote unprivileged remote user user: @@ -55,11 +65,12 @@ state: absent connection: local - - name: Remove circular symbolic link + - name: Remove symbolic link file: - path: '{{ role_path }}/files/subdir/subdir1/circles' + path: '{{ role_path }}/files/subdir/subdir1/{{ item.key }}' state: absent connection: local + with_dict: "{{ symlinks }}" - name: Remote unprivileged remote user user: diff --git a/test/integration/targets/template_jinja2_latest/roles/template b/test/integration/targets/template_jinja2_latest/roles/template deleted file mode 120000 index 8bed5e1595..0000000000 --- a/test/integration/targets/template_jinja2_latest/roles/template +++ /dev/null @@ -1 +0,0 @@ -../../template \ No newline at end of file diff --git a/test/integration/targets/template_jinja2_latest/runme.sh b/test/integration/targets/template_jinja2_latest/runme.sh index 3c705e19a0..9f61e4879c 100755 --- a/test/integration/targets/template_jinja2_latest/runme.sh +++ b/test/integration/targets/template_jinja2_latest/runme.sh @@ -18,4 +18,7 @@ source "${MYTMPDIR}/jinja2/bin/activate" pip install -U jinja2 +ANSIBLE_ROLES_PATH="$(dirname "$(pwd)")" +export ANSIBLE_ROLES_PATH + ansible-playbook -i ../../inventory main.yml -e @../../integration_config.yml -v "$@" diff --git a/test/legacy/roles/setup_ec2 b/test/legacy/roles/setup_ec2 deleted file mode 120000 index 6dd2acb9e8..0000000000 --- a/test/legacy/roles/setup_ec2 +++ /dev/null @@ -1 +0,0 @@ -../../integration/targets/setup_ec2 \ No newline at end of file diff --git a/test/legacy/roles/setup_ec2/defaults/main.yml b/test/legacy/roles/setup_ec2/defaults/main.yml new file mode 100644 index 0000000000..fb1f88b1ec --- /dev/null +++ b/test/legacy/roles/setup_ec2/defaults/main.yml @@ -0,0 +1,2 @@ +--- +resource_prefix: 'ansible-testing-' diff --git a/test/legacy/roles/setup_ec2/tasks/common.yml b/test/legacy/roles/setup_ec2/tasks/common.yml new file mode 100644 index 0000000000..bf23f539a9 --- /dev/null +++ b/test/legacy/roles/setup_ec2/tasks/common.yml @@ -0,0 +1,119 @@ +--- + +# ============================================================ +- name: test with no parameters + action: "{{module_name}}" + register: result + ignore_errors: true + +- name: assert failure when called with no parameters + assert: + that: + - 'result.failed' + - 'result.msg == "missing required arguments: name"' + +# ============================================================ +- name: test with only name + action: "{{module_name}} name={{ec2_key_name}}" + register: result + ignore_errors: true + +- name: assert failure when called with only 'name' + assert: + that: + - 'result.failed' + - 'result.msg == "Either region or ec2_url must be specified"' + +# ============================================================ +- name: test invalid region parameter + action: "{{module_name}} name='{{ec2_key_name}}' region='asdf querty 1234'" + register: result + ignore_errors: true + +- name: assert invalid region parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("value of region must be one of:")' + +# ============================================================ +- name: test valid region parameter + action: "{{module_name}} name='{{ec2_key_name}}' region='{{ec2_region}}'" + register: result + ignore_errors: true + +- name: assert valid region parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# ============================================================ +- name: test environment variable EC2_REGION + action: "{{module_name}} name='{{ec2_key_name}}'" + environment: + EC2_REGION: '{{ec2_region}}' + register: result + ignore_errors: true + +- name: assert environment variable EC2_REGION + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# ============================================================ +- name: test invalid ec2_url parameter + action: "{{module_name}} name='{{ec2_key_name}}'" + environment: + EC2_URL: bogus.example.com + register: result + ignore_errors: true + +- name: assert invalid ec2_url parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# ============================================================ +- name: test valid ec2_url parameter + action: "{{module_name}} name='{{ec2_key_name}}'" + environment: + EC2_URL: '{{ec2_url}}' + register: result + ignore_errors: true + +- name: assert valid ec2_url parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# ============================================================ +- name: test credentials from environment + action: "{{module_name}} name='{{ec2_key_name}}'" + environment: + EC2_REGION: '{{ec2_region}}' + EC2_ACCESS_KEY: bogus_access_key + EC2_SECRET_KEY: bogus_secret_key + register: result + ignore_errors: true + +- name: assert ec2_key with valid ec2_url + assert: + that: + - 'result.failed' + - '"EC2ResponseError: 401 Unauthorized" in result.msg' + +# ============================================================ +- name: test credential parameters + action: "{{module_name}} name='{{ec2_key_name}}' ec2_region='{{ec2_region}}' ec2_access_key=bogus_access_key ec2_secret_key=bogus_secret_key" + register: result + ignore_errors: true + +- name: assert credential parameters + assert: + that: + - 'result.failed' + - '"EC2ResponseError: 401 Unauthorized" in result.msg' diff --git a/test/legacy/roles/setup_ec2/vars/main.yml b/test/legacy/roles/setup_ec2/vars/main.yml new file mode 100644 index 0000000000..3d7209ef1b --- /dev/null +++ b/test/legacy/roles/setup_ec2/vars/main.yml @@ -0,0 +1,3 @@ +--- +ec2_url: ec2.amazonaws.com +ec2_region: us-east-1 diff --git a/test/legacy/roles/setup_sshkey b/test/legacy/roles/setup_sshkey deleted file mode 120000 index 7f1d3b39fa..0000000000 --- a/test/legacy/roles/setup_sshkey +++ /dev/null @@ -1 +0,0 @@ -../../integration/targets/setup_sshkey \ No newline at end of file diff --git a/test/legacy/roles/setup_sshkey/tasks/main.yml b/test/legacy/roles/setup_sshkey/tasks/main.yml new file mode 100644 index 0000000000..18c571b671 --- /dev/null +++ b/test/legacy/roles/setup_sshkey/tasks/main.yml @@ -0,0 +1,55 @@ +# (c) 2014, James Laska + +# 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 . + +- name: create a temp file + tempfile: + state: file + register: sshkey_file + tags: + - prepare + +- name: generate sshkey + shell: echo 'y' | ssh-keygen -P '' -f {{ sshkey_file.path }} + tags: + - prepare + +- name: create another temp file + tempfile: + state: file + register: another_sshkey_file + tags: + - prepare + +- name: generate another_sshkey + shell: echo 'y' | ssh-keygen -P '' -f {{ another_sshkey_file.path }} + tags: + - prepare + +- name: record fingerprint + shell: openssl rsa -in {{ sshkey_file.path }} -pubout -outform DER 2>/dev/null | openssl md5 -c + register: fingerprint + tags: + - prepare + +- name: set facts for future roles + set_fact: + sshkey: '{{ sshkey_file.path }}' + key_material: "{{ lookup('file', sshkey_file.path ~ '.pub') }}" + another_key_material: "{{ lookup('file', another_sshkey_file.path ~ '.pub') }}" + fingerprint: '{{ fingerprint.stdout.split()[1] }}' + tags: + - prepare diff --git a/test/runner/lib/sanity/import.py b/test/runner/lib/sanity/import.py index 5f63ac2110..7ff5212eb9 100644 --- a/test/runner/lib/sanity/import.py +++ b/test/runner/lib/sanity/import.py @@ -20,6 +20,7 @@ from lib.util import ( find_python, read_lines_without_comments, parse_to_list_of_dict, + make_dirs, ) from lib.ansible_util import ( @@ -81,9 +82,24 @@ class ImportTest(SanityMultipleVersion): if not args.explain: os.symlink(os.path.abspath('test/sanity/import/importer.py'), importer_path) + # create a minimal python library + python_path = os.path.abspath('test/runner/.tox/import/lib') + ansible_path = os.path.join(python_path, 'ansible') + ansible_init = os.path.join(ansible_path, '__init__.py') + ansible_link = os.path.join(ansible_path, 'module_utils') + + if not args.explain: + make_dirs(ansible_path) + + with open(ansible_init, 'w'): + pass + + if not os.path.exists(ansible_link): + os.symlink('../../../../../../lib/ansible/module_utils', ansible_link) + # activate the virtual environment env['PATH'] = '%s:%s' % (virtual_environment_bin, env['PATH']) - env['PYTHONPATH'] = os.path.abspath('test/sanity/import/lib') + env['PYTHONPATH'] = python_path # make sure coverage is available in the virtual environment if needed if args.coverage: diff --git a/test/sanity/code-smell/symlinks.json b/test/sanity/code-smell/symlinks.json new file mode 100644 index 0000000000..39ac4bd57f --- /dev/null +++ b/test/sanity/code-smell/symlinks.json @@ -0,0 +1,4 @@ +{ + "always": true, + "output": "path-message" +} diff --git a/test/sanity/code-smell/symlinks.py b/test/sanity/code-smell/symlinks.py new file mode 100755 index 0000000000..ec5c72635b --- /dev/null +++ b/test/sanity/code-smell/symlinks.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +import os + + +def main(): + skip_dirs = set([ + '.tox', + ]) + + for root, dirs, files in os.walk('.'): + for skip_dir in skip_dirs: + if skip_dir in dirs: + dirs.remove(skip_dir) + + if root == '.': + root = '' + elif root.startswith('./'): + root = root[2:] + + for file in files: + path = os.path.join(root, file) + + if not os.path.exists(path): + print('%s: broken symlinks are not allowed' % path) + + for directory in dirs: + path = os.path.join(root, directory) + + if os.path.islink(path): + print('%s: symlinks to directories are not allowed' % path) + + +if __name__ == '__main__': + main() diff --git a/test/sanity/import/lib/ansible/__init__.py b/test/sanity/import/lib/ansible/__init__.py deleted file mode 100644 index efba395dd1..0000000000 --- a/test/sanity/import/lib/ansible/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Empty placeholder for import sanity test.""" diff --git a/test/sanity/import/lib/ansible/module_utils b/test/sanity/import/lib/ansible/module_utils deleted file mode 120000 index fd236e25b5..0000000000 --- a/test/sanity/import/lib/ansible/module_utils +++ /dev/null @@ -1 +0,0 @@ -../../../../../lib/ansible/module_utils \ No newline at end of file