diff --git a/.ansible-lint b/.ansible-lint index 96f8e876b..4ae3be0d1 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -1,4 +1,11 @@ --- +exclude_paths: + - ./roles/infrared/ + skip_list: + - '206' + - '306' - '403' + - '502' + - '701' diff --git a/.gitignore b/.gitignore index 876ab628d..4992e2ac4 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ doc/build/* dist/ etc/*.sample tobiko_results* +test_results* zuul/versioninfo # Files created by releasenotes build diff --git a/linters-requirements.txt b/linters-requirements.txt index 877d40a45..aa08616d7 100644 --- a/linters-requirements.txt +++ b/linters-requirements.txt @@ -1,6 +1,6 @@ # pep8 and flake8 requirements -ansible-lint < 4 # MIT +ansible-lint==4.2.0 # MIT flake8==2.5.5 # MIT flake8-import-order==0.12 # LGPLv3 mypy>=0.740 # MIT diff --git a/roles/infrared.yaml b/roles/infrared.yaml new file mode 100644 index 000000000..915917eff --- /dev/null +++ b/roles/infrared.yaml @@ -0,0 +1,54 @@ +--- + +- hosts: '{{ test_host }}' + gather_facts: yes + any_errors_fatal: yes + roles: + + - role: tobiko-common + + - role: tobiko-deploy + vars: + src_dir: '{{ tobiko_src_dir }}' + dest_dir: '{{ tobiko_dir }}' + git_repo: '{{ tobiko_git_repo }}' + git_refspec: '{{ tobiko_git_refspec }}' + git_version: '{{ tobiko_git_version }}' + when: + - test_stage in ['all', 'pre-run', 'deploy', 'deploy-tobiko'] + + - role: tobiko-deploy + vars: + src_dir: '{{ test_src_dir }}' + dest_dir: '{{ test_dir }}' + git_repo: '{{ test_git_repo }}' + git_refspec: '{{ test_git_refspec }}' + git_version: '{{ test_git_version }}' + when: + - test_stage in ['all', 'pre-run', 'deploy', 'deploy-test'] + - tobiko_dir != test_dir + + - role: tobiko-configure + when: + - test_stage in ['all', 'pre-run', 'configure'] + + - role: tobiko-tox + ignore_errors: yes + when: + - test_stage in ['all', 'run', 'tox'] + + - role: tobiko-collect + when: + - test_stage in ['all', 'post-run', 'collect'] + + +- hosts: '{{ test_host }}' + tasks: + + - name: 'report test failure' + debug: + msg: 'Test cases have failed' + failed_when: yes + when: + - run_tox is defined + - run_tox is failed diff --git a/roles/plugin.spec b/roles/plugin.spec new file mode 100644 index 000000000..abc6520d7 --- /dev/null +++ b/roles/plugin.spec @@ -0,0 +1,122 @@ +--- + +config: + plugin_type: test + entry_point: infrared.yaml + + +subparsers: + + tobiko: + description: Deploy, configure and execute tobiko test cases + include_groups: ["Ansible options", "Inventory", "Common options", "Answers file"] + groups: + + - title: Topology options + options: + host: + type: Value + required: True + default: localhost + help: Target host where test cases are deployed and executed + ansible_variable: test_host + + - title: Control flow + options: + stage: + type: Value + default: all + ansible_variable: test_stage + + - title: Deploy stage + options: + clean-deploy-dir: + type: Flag + help: Cleanup directory where test cases will be downloaded + ansible_variable: clean_deploy_dir + tobiko-src-dir: + type: Value + help: Local directory where tobiko scripts are found + ansible_variable: tobiko_src_dir + tobiko-dir: + type: Value + help: Test host directory where Tobiko has to be deployed to + ansible_variable: tobiko_dir + tobiko-version: + type: Value + help: Git version to be used for checking out Tobiko scripts + ansible_variable: tobiko_git_version + tobiko-refspec: + type: Value + help: Git refspect to be used for checking out Tobiko scripts + ansible_variable: tobiko_git_refspec + + test-src-dir: + type: Value + help: Local directory where test cases (and tox.ini file) are found + ansible_variable: test_src_dir + test-dir: + type: Value + help: Test host directory where test cases (and tox.ini file) are found + ansible_variable: test_dir + test-version: + type: Value + help: Git version to be used for checking out test scripts + ansible_variable: test_git_version + test-refspec: + type: Value + help: Git refspect to be used for checking out test scripts + ansible_variable: test_git_refspec + + - title: Configure stage + options: + config: + type: Value + help: tobiko.conf file location + ansible_variable: test_conf_file + debug: + type: Value + help: enable/disable verbose log entries in tests results log file + ansible_variable: test_log_debug + + - title: Run tox stage + options: + tox-dir: + type: Value + help: directory from where run tox (typically test_dir) + ansible_variable: tox_dir + tox-command: + type: Value + help: command to be executed for tox (typically tox) + ansible_variable: tox_command + tox-envlist: + type: Value + help: tox environment list to be executed + ansible_variable: tox_envlist + tox-extra-args: + type: Value + help: extra options to be passed to Tox + ansible_variable: tox_extra_args + test-report-dir: + type: Value + help: directory where to store test report files + ansible_variable: test_report_dir + test-report-name: + type: Value + help: prefix used to create report file names + ansible_variable: test_report_name + test-log-file: + type: Value + help: test cases log file + ansible_variable: test_log_file + + - title: Collect stage + options: + collect-dir: + type: Value + help: local directory where report files are going to be copied to + ansible_variable: test_collect_dir + compress-collected: + type: Flag + help: compress report files before collecting them + ansible_variable: compress_collected_files diff --git a/roles/tobiko-collect/defaults/main.yaml b/roles/tobiko-collect/defaults/main.yaml new file mode 100644 index 000000000..0b887804e --- /dev/null +++ b/roles/tobiko-collect/defaults/main.yaml @@ -0,0 +1,10 @@ +--- + + +report_dir: '{{ test_report_dir | realpath }}' +report_files: '{{ test_report_files }}' +report_name: '{{ test_report_name }}' +collect_dir: '{{ test_collect_dir | realpath }}' + +compress_collected_files: no +report_files_suffix: '{% if (compress_collected_files | bool) %}.gz{% endif %}' diff --git a/roles/tobiko-collect/meta/main.yaml b/roles/tobiko-collect/meta/main.yaml new file mode 100644 index 000000000..0d4361583 --- /dev/null +++ b/roles/tobiko-collect/meta/main.yaml @@ -0,0 +1,4 @@ +--- + +dependencies: + - role: tobiko-common diff --git a/roles/tobiko-collect/tasks/main.yaml b/roles/tobiko-collect/tasks/main.yaml new file mode 100644 index 000000000..9c70d81e7 --- /dev/null +++ b/roles/tobiko-collect/tasks/main.yaml @@ -0,0 +1,55 @@ +--- + +- name: "ensures local directory '{{ collect_dir }}' exists" + file: + path: '{{ collect_dir }}' + state: directory + delegate_to: 127.0.0.1 + + +- name: "look for report files in {{ report_dir }}" + find: + paths: + - "{{ report_dir }}" + patterns: + - "{{ report_name }}*.log" + - "{{ report_name }}*.subunit" + - "{{ report_name }}*.html" + - "{{ report_name }}*.xml" + register: find_report_files + + +- name: "add found report files" + set_fact: + report_files: '{{ (( find_report_files.files | json_query("[*].path")) + report_files) | unique }}' + + +- name: "check if report files exists" + stat: + path: "{{ item }}" + get_checksum: no + register: stat_report_files + loop: '{{ report_files }}' + + +- name: "filter out non existing files" + set_fact: + report_files: '{{ stat_report_files.results | json_query("[?stat.exists].stat.path") }}' + + +- name: "compress report files" + when: compress_collected_files | bool + archive: + path: '{{ item }}' + loop: '{{ report_files }}' + + +- name: "collect report files to local directory '{{ collect_dir }}'" + synchronize: + dest: '{{ collect_dir }}' + mode: pull + src: "{{ item }}{{ report_files_suffix }}" + use_ssh_args: yes + recursive: yes + loop: '{{ report_files }}' + ignore_errors: yes diff --git a/roles/tobiko-common/defaults/main.yaml b/roles/tobiko-common/defaults/main.yaml new file mode 100644 index 000000000..3edd82166 --- /dev/null +++ b/roles/tobiko-common/defaults/main.yaml @@ -0,0 +1,49 @@ +--- + +# --- Tobiko deploy options --------------------------------------------------- + +user_home: '{{ ansible_env.get("HOME", "~")}}' + +tobiko_dir: '{{ user_home }}/src/tobiko' +tobiko_src_dir: '{{ role_path | dirname | dirname }}' +tobiko_git_repo: 'https://opendev.org/x/tobiko.git' +tobiko_git_refspec: '' +tobiko_git_version: '' + + +# --- Test deploy options ----------------------------------------------------- + +test_dir: '{{ tobiko_dir }}' +test_src_dir: '{{ tobiko_src_dir }}' +test_git_repo: '{{ tobiko_git_repo }}' +test_git_refspec: '' +test_git_version: '' + + +# --- Test configuration options ---------------------------------------------- + +# Configuration options +test_conf_file: '{{ test_dir }}/tobiko.conf' + +test_conf: {} + +# Logging options +test_log_debug: true + + +# --- Test report options ----------------------------------------------------- + +# Remote directory where test cases shoulw write report files to +test_report_dir: "{{ test_dir }}" +test_report_files: + - '{{ test_conf_file }}' + - '{{ test_log_file }}' + +# Test report files prefix +test_report_name: test_results + +# Log file where test cases should write logging messages to +test_log_file: "{{ test_report_dir }}/tobiko.log" + +# Local where test cases results are being collected to +test_collect_dir: "{{ test_src_dir }}/{{ test_report_name }}" diff --git a/roles/tobiko-common/tasks/main.yaml b/roles/tobiko-common/tasks/main.yaml new file mode 100644 index 000000000..a9092489a --- /dev/null +++ b/roles/tobiko-common/tasks/main.yaml @@ -0,0 +1,14 @@ +--- + +- name: "expand actual user home directory" + command: 'echo "{{ user_home }}"' + register: expand_user_home + + +- name: "update user home directory" + set_fact: + user_home: '{{ expand_user_home.stdout.strip() | realpath }}' + + +- name: "show actual user home directory" + debug: var=user_home diff --git a/roles/tobiko-configure/defaults/main.yaml b/roles/tobiko-configure/defaults/main.yaml new file mode 100644 index 000000000..d5f5922ee --- /dev/null +++ b/roles/tobiko-configure/defaults/main.yaml @@ -0,0 +1,19 @@ +--- + +# Configuration options +conf_file: '{{ test_conf_file | realpath }}' + +default_conf: + DEFAULT: + debug: "{{ log_debug }}" + log_dir: "{{ log_file | dirname }}" + log_file: "{{ log_file | basename }}" + +conf: {} + +# Logging options +log_debug: '{{ test_log_debug | bool }}' +log_file: "{{ test_log_file | realpath }}" + +# OpenStack client credentials +stackrc_file: '{{ user_home }}/overcloudrc' diff --git a/roles/tobiko-configure/meta/main.yaml b/roles/tobiko-configure/meta/main.yaml new file mode 100644 index 000000000..0d4361583 --- /dev/null +++ b/roles/tobiko-configure/meta/main.yaml @@ -0,0 +1,4 @@ +--- + +dependencies: + - role: tobiko-common diff --git a/roles/tobiko-configure/tasks/main.yaml b/roles/tobiko-configure/tasks/main.yaml new file mode 100644 index 000000000..bc63b82b1 --- /dev/null +++ b/roles/tobiko-configure/tasks/main.yaml @@ -0,0 +1,55 @@ +--- + +- name: "list configuration options" + set_fact: + conf_yaml: | + {% for section, options in (sections.items() | sort) %} + {% for option, value in (options.items() | sort) %} + - section: "{{ section }}" + option: "{{ option }}" + value: "{{ value }}" + {% endfor %} + {% endfor %} + vars: + sections: "{{ default_conf | combine(conf, recursive=True) }}" + + +- name: "show tobiko configuration" + debug: + msg: | + Tobiko configuration: + {{ conf_yaml }} + + +- name: "generate '{{ conf_file }}' file" + ini_file: + path: "{{ conf_file }}" + section: "{{ item.section }}" + option: "{{ item.option }}" + value: "{{ item.value }}" + mode: '0644' + when: + - item.section + - item.option + - item.value + loop: "{{ conf_yaml | from_yaml | list }}" + + +- name: "read {{ conf_file }} file" + slurp: + src: "{{ conf_file }}" + register: read_conf_file + + +- name: "show {{ conf_file }} file" + debug: + msg: "{{ read_conf_file['content'] | b64decode }}" + + +# TODO (fressi): move it to a Tobiko python fixture +- name: Set permissive quotas for instances and cores + shell: | + source "{{ stackrc_file }}" + openstack quota set --instances -1 admin + openstack quota set --cores -1 admin + ignore_errors: yes diff --git a/roles/tobiko-deploy/defaults/main.yaml b/roles/tobiko-deploy/defaults/main.yaml new file mode 100644 index 000000000..e35d46eb6 --- /dev/null +++ b/roles/tobiko-deploy/defaults/main.yaml @@ -0,0 +1,11 @@ +--- + +# Directory where files has to be deployed to +src_dir: '{{ tobiko_src_dir }}' +dest_dir: '{{ tobiko_dir }}' + +git_repo: '{{ tobiko_git_repo }}' +git_refspec: '{{ tobiko_git_refspec }}' +git_version: '{{ tobiko_git_version }}' + +clean_deploy_dir: false diff --git a/roles/tobiko-deploy/meta/main.yaml b/roles/tobiko-deploy/meta/main.yaml new file mode 100644 index 000000000..0d4361583 --- /dev/null +++ b/roles/tobiko-deploy/meta/main.yaml @@ -0,0 +1,4 @@ +--- + +dependencies: + - role: tobiko-common diff --git a/roles/tobiko-deploy/tasks/main.yaml b/roles/tobiko-deploy/tasks/main.yaml new file mode 100644 index 000000000..4f863b622 --- /dev/null +++ b/roles/tobiko-deploy/tasks/main.yaml @@ -0,0 +1,57 @@ +--- + +- name: "clean directory {{ dest_dir }}" + file: + path: "{{ dest_dir | realpath }}" + state: absent + when: + - clean_deploy_dir | bool + - | + (src_dir | length) == 0 or + (git_version | length) > 0 or + (git_refspec | length) == 0 + + +- name: "create directory {{ dest_dir }}" + file: + path: "{{ dest_dir | realpath }}" + state: directory + + +- name: "copy '{{ src_dir }}' to '{{ dest_dir }}'" + synchronize: + src: "{{ src_dir | realpath }}/." + dest: "{{ dest_dir | realpath }}" + use_ssh_args: yes + recursive: yes + delete: "{{ clean_deploy_dir | bool }}" + rsync_opts: + - "--exclude-from={{ src_dir | realpath }}/.gitignore" + when: + - (src_dir | length) > 0 + - (git_version | length) == 0 + - (git_refspec | length) == 0 + + +- name: "checkout test cases from '{{ git_repo }}[{{ git_refspec or git_version }}]' to '{{ dest_dir }}'" + git: + dest: '{{ dest_dir }}' + repo: '{{ git_repo }}' + refspec: '{{ git_refspec }}' + version: '{%if (git_refspec | length) %}FETCH_HEAD{% else %}{{ git_version }}{% endif %}' + force: yes + when: | + (src_dir | length) == 0 or + (git_version | length) > 0 or + (git_refspec | length) > 0 + + +- name: "get last change details" # noqa 303 + command: + chdir: "{{ dest_dir }}" + cmd: git log -n 1 + register: get_git_log + + +- name: "show last change details" + debug: var=get_git_log.stdout_lines diff --git a/roles/tobiko-tox/defaults/main.yaml b/roles/tobiko-tox/defaults/main.yaml new file mode 100644 index 000000000..866c45f58 --- /dev/null +++ b/roles/tobiko-tox/defaults/main.yaml @@ -0,0 +1,12 @@ +--- + +# Directory where test cases has been deployed to +tox_dir: '{{ test_dir | realpath }}' +tox_command: "{{ tobiko_dir | realpath }}/tools/ci/tox" +tox_envlist: py36 +tox_extra_args: '' + +tox_command_line: '{{ tox_command }} "-e{{ tox_envlist }}" {{ tox_extra_args }}' + +tox_report_dir: "{{ test_report_dir | realpath }}" +tox_report_name: '{{ test_report_name }}_{{ tox_envlist }}' diff --git a/roles/tobiko-tox/meta/main.yaml b/roles/tobiko-tox/meta/main.yaml new file mode 100644 index 000000000..0d4361583 --- /dev/null +++ b/roles/tobiko-tox/meta/main.yaml @@ -0,0 +1,4 @@ +--- + +dependencies: + - role: tobiko-common diff --git a/roles/tobiko-tox/tasks/main.yaml b/roles/tobiko-tox/tasks/main.yaml new file mode 100644 index 000000000..1db799bb9 --- /dev/null +++ b/roles/tobiko-tox/tasks/main.yaml @@ -0,0 +1,30 @@ +--- + +- name: "Run test Tox envlist '{{ tox_envlist }}' on direcory '{{ tox_dir }}'" + shell: + chdir: "{{ tox_dir }}" + cmd: | + set -x + {{ tox_command }} -e "{{ tox_envlist }}" {{ tox_extra_args }} + exit_status=$? + {{ tox_command }} -c '{{ tobiko_dir }}' -e report + exit "${exit_status}" + register: + run_tox + environment: + TOBIKO_TEST_REPORT_DIR: "{{ tox_report_dir }}" + TOBIKO_TEST_REPORT_NAME: "{{ tox_report_name }}" + ignore_errors: yes + + +- name: "Show test cases results" + debug: var=run_tox.stdout_lines + when: + - (run_tox.stdout_lines | length) > 0 + + +- name: "Show test cases errors" + debug: var=run_tox.stderr_lines + when: + - (run_tox.stderr_lines | length) > 0 + failed_when: run_tox is failed diff --git a/tox.ini b/tox.ini index ccece03dd..d507b58a6 100644 --- a/tox.ini +++ b/tox.ini @@ -186,11 +186,14 @@ passenv = IR_* setenv = {[testenv:venv]setenv} - IR_HOME={env:IR_HOME:{toxinidir}/.infrared} - IR_TOBIKO_PLUGIN={env:IR_TOBIKO_PLUGIN:{toxinidir}/roles/infrared} + IR_COMMAND={env:IR_COMMAND:{toxinidir}/tools/ci/ir} + IR_HOME={env:IR_HOME:{envdir}/home/infrared} + whitelist_externals = * commands = - bash {toxinidir}/tools/ci/ir {posargs:tobiko} + bash -c '{env:IR_COMMAND} plugin remove tobiko || true' + {env:IR_COMMAND} plugin add {toxinidir}/roles + {env:IR_COMMAND} tobiko --tobiko-src-dir {toxinidir} {posargs} # --- documentation environments ---------------------------------------------- diff --git a/zuul.d/infrared.yaml b/zuul.d/infrared.yaml index af8e91920..954b729fc 100644 --- a/zuul.d/infrared.yaml +++ b/zuul.d/infrared.yaml @@ -10,6 +10,7 @@ Run tobiko infrared plugin vars: tox_envlist: infrared + # tox_extra_args: -- --tox_envlist functional bindep_profile: test python_version: 3.6 # compile and install python3.8 from source code