├── docs ├── _templates │ └── .empty ├── changelog.rst ├── developers │ ├── development.rst │ └── index.rst ├── _static │ ├── teflo_pipeline.png │ ├── teflo_workflow.png │ ├── teflo_scenario_resource.png │ ├── teflo_scenario_resource_task.png │ └── theme_override.css ├── users │ ├── index.rst │ ├── localhost.rst │ ├── definitions │ │ ├── resource_check.rst │ │ ├── timeout.rst │ │ └── report.rst │ ├── examples.rst │ ├── scenario_descriptor.rst │ ├── configuration.rst │ └── variable_data.rst ├── contents.rst.inc ├── Makefile ├── link_mapping ├── wiki-sanitizer.py ├── contact.rst ├── index.rst └── glossary.rst ├── tests ├── assets │ ├── artifacts │ │ ├── host01 │ │ │ └── sample1.xml │ │ ├── host02 │ │ │ └── sample2.xml │ │ └── host03 │ │ │ ├── sample1.xml │ │ │ ├── sample2.xml │ │ │ └── sample.xml │ ├── show_test_var.yml │ ├── vars_data.yml │ ├── test_var_file.yml │ ├── vars_files │ │ ├── vardatatwo.yml │ │ └── vardata.yml │ ├── test_email_template.jinja │ ├── malformed_included_file.yml │ ├── script-results-xyz.json │ ├── common.yml │ ├── no_include.yml │ ├── correct_include_descriptor.yml │ ├── wrong_include_descriptor.yml │ ├── empty_include.yml │ ├── testvault.cfg │ ├── wrong_include_sdf.yml │ ├── scenario_graph_basic_test │ │ ├── sdf10.yml │ │ ├── sdf13.yml │ │ ├── sdf5.yml │ │ ├── sdf3.yml │ │ ├── sdf4.yml │ │ ├── sdf6.yml │ │ ├── sdf9.yml │ │ ├── sdf11.yml │ │ ├── sdf.yml │ │ ├── sdf12.yml │ │ ├── sdf7.yml │ │ ├── sdf0.yml │ │ ├── sdf1.yml │ │ ├── sdf2.yml │ │ └── sdf8.yml │ ├── show_vars_data.yml │ ├── single_template.yml │ ├── missing_colon_sdf.yml │ ├── wrong_space_sdf.yml │ ├── schemas │ │ └── schema_test.yml │ ├── multiple_template.yml │ ├── remote_include.yml │ ├── descriptor.yml │ ├── test_nested_var_file.yml │ ├── credentials_test.key │ ├── test_template_render.yml │ └── teflo.cfg ├── localhost_scenario │ ├── variable.yml │ ├── variable_1.yml │ ├── ansible │ │ ├── group_vars │ │ │ └── all.yml │ │ ├── system_info.yml │ │ ├── test_echo_var.yml │ │ ├── list_block_devices.yml │ │ ├── test_playbook_tasks.yml │ │ ├── tests │ │ │ └── test_execute_playbook.yml │ │ ├── template_host_test_playbook_tasks.yml │ │ └── variable_test_playbook.yml │ ├── teflo.cfg │ ├── ansible.cfg │ ├── scripts │ │ ├── hello_world.py │ │ ├── cleanup_artifacts.sh │ │ └── add_two_numbers.sh │ ├── sdf1_test_jinja.yml │ ├── sdf2_test_jinja.yml │ ├── sdf4_test_jinja.yml │ ├── sample_artifacts │ │ ├── SampleTest.log │ │ └── SampleTest.xml │ ├── sdf3_test_jinja.yml │ ├── sdf0_test_jinja.yml │ ├── sdf_remotes2.yml │ ├── s_test_gv.yml │ ├── sdf_library2.yml │ ├── sdf_remotes1.yml │ ├── sdf_remotes4.yml │ ├── sdf_library3.yml │ ├── sdf_library4.yml │ ├── sdf_remotes3.yml │ └── sdf_library1.yml ├── pytest.ini └── functional │ ├── test_misc.py │ ├── test_ansible_vault.py │ ├── test_config_class.py │ ├── conftest.py │ ├── test_action_orchestrator.py │ ├── test_execute_manager.py │ ├── test_notification_emitter.py │ └── test_exceptions.py ├── examples └── docs-usage │ ├── requirements.yml │ ├── teflo_example.cfg │ ├── resource_check.yml │ ├── resource_labels.yml │ ├── notification.yml │ ├── include.yml │ ├── provision.yml │ └── configuration.yml ├── .bumpversion.cfg ├── setup.cfg ├── shell_tox.sh ├── teflo ├── notifiers │ ├── ext │ │ ├── email │ │ │ ├── templates │ │ │ │ ├── email_on_start_txt_template.jinja │ │ │ │ └── email_txt_template.jinja │ │ │ ├── schema │ │ │ │ ├── schema.yml │ │ │ │ └── email_extensions.py │ │ │ └── __init__.py │ │ └── __init__.py │ ├── __init__.py │ └── notification_emitter.py ├── executors │ ├── ext │ │ ├── __init__.py │ │ └── ansible_executor_plugin │ │ │ ├── __init__.py │ │ │ └── files │ │ │ ├── extensions.py │ │ │ └── schema.yml │ ├── __init__.py │ └── execute_manager.py ├── orchestrators │ ├── ext │ │ ├── __init__.py │ │ └── ansible_orchestrator_plugin │ │ │ ├── __init__.py │ │ │ └── files │ │ │ ├── schema.yml │ │ │ └── extensions.py │ ├── __init__.py │ └── action_orchestrator.py ├── provisioners │ ├── ext │ │ ├── bkr_client_plugin │ │ │ ├── __init__.py │ │ │ ├── extensions.py │ │ │ └── schema.yml │ │ ├── os_libcloud_plugin │ │ │ ├── __init__.py │ │ │ └── schema.yml │ │ └── __init__.py │ └── __init__.py ├── utils │ └── __init__.py ├── static │ └── __init__.py ├── importers │ ├── __init__.py │ └── artifact_importer.py ├── __init__.py ├── providers │ └── __init__.py ├── resources │ └── __init__.py ├── tasks │ ├── __init__.py │ ├── validate.py │ ├── notification.py │ ├── execute.py │ ├── orchestrate.py │ ├── provision.py │ ├── report.py │ └── cleanup.py ├── _compat.py └── files │ ├── extensions.py │ └── schema.yml ├── AUTHORS ├── .pre-commit-config.yaml ├── .gitignore ├── test-requirements.txt ├── .github └── workflows │ ├── bumptag.yml │ ├── pushtopypi.yml │ └── run_unit_tests.yml ├── readthedocs.yml ├── MANIFEST.in ├── Makefile ├── tox.ini ├── README.rst └── setup.py /docs/_templates/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/assets/artifacts/host01/sample1.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/assets/artifacts/host02/sample2.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/assets/show_test_var.yml: -------------------------------------------------------------------------------- 1 | var: hellohello 2 | -------------------------------------------------------------------------------- /tests/localhost_scenario/variable.yml: -------------------------------------------------------------------------------- 1 | ip: 127.0.1.1 -------------------------------------------------------------------------------- /tests/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | cache_dir=.cache 3 | -------------------------------------------------------------------------------- /tests/assets/vars_data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | asset_name: unit_test -------------------------------------------------------------------------------- /tests/localhost_scenario/variable_1.yml: -------------------------------------------------------------------------------- 1 | name: teflo_user -------------------------------------------------------------------------------- /tests/assets/test_var_file.yml: -------------------------------------------------------------------------------- 1 | --- 2 | asset_name: teflo_test -------------------------------------------------------------------------------- /tests/assets/vars_files/vardatatwo.yml: -------------------------------------------------------------------------------- 1 | secondkey: secondval 2 | -------------------------------------------------------------------------------- /tests/assets/vars_files/vardata.yml: -------------------------------------------------------------------------------- 1 | --- 2 | firstkey: firstval 3 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | .. include:: ../CHANGES.rst 5 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ansible_user: ansible_user=fedora 4 | -------------------------------------------------------------------------------- /docs/developers/development.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | .. include:: ../../CONTRIBUTE.rst 5 | -------------------------------------------------------------------------------- /docs/_static/teflo_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatQE/teflo/HEAD/docs/_static/teflo_pipeline.png -------------------------------------------------------------------------------- /docs/_static/teflo_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatQE/teflo/HEAD/docs/_static/teflo_workflow.png -------------------------------------------------------------------------------- /tests/assets/test_email_template.jinja: -------------------------------------------------------------------------------- 1 | Hello {{ user }}, 2 | 3 | This is a Func Test Email. 4 | 5 | Thanks, 6 | 7 | Tester -------------------------------------------------------------------------------- /docs/_static/teflo_scenario_resource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatQE/teflo/HEAD/docs/_static/teflo_scenario_resource.png -------------------------------------------------------------------------------- /docs/_static/teflo_scenario_resource_task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatQE/teflo/HEAD/docs/_static/teflo_scenario_resource_task.png -------------------------------------------------------------------------------- /examples/docs-usage/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: https://github.com/collection/path 4 | type: git 5 | version: main -------------------------------------------------------------------------------- /tests/assets/malformed_included_file.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: common 3 | description: common descriptor 4 | 5 | credentials: 6 | - name: provider 7 | -------------------------------------------------------------------------------- /tests/assets/script-results-xyz.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "err": "", 4 | "host_name": "host1", 5 | "rc": "0" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/system_info.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ' {{ hosts }}' 3 | tasks: 4 | - name: simple playbook 5 | debug: 6 | msg: 'hello' 7 | -------------------------------------------------------------------------------- /tests/assets/common.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: common 3 | description: common descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | provision: 9 | 10 | orchestrate: 11 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/test_echo_var.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ' {{ hosts }}' 3 | tasks: 4 | - name: simple playbook 5 | debug: 6 | msg: ' {{ ansible_user }} ' 7 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 2.4.1 3 | 4 | [bumpversion:file:teflo/__init__.py] 5 | 6 | [bumpversion:file:docs/conf.py] 7 | 8 | [bumpversion:file:setup.cfg] 9 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | 4 | [build_sphinx] 5 | source-dir = docs 6 | build-dir = docs/_build 7 | all_files = 1 8 | project = Teflo 9 | version = 2.4.1 10 | release = 2.4.1 11 | -------------------------------------------------------------------------------- /shell_tox.sh: -------------------------------------------------------------------------------- 1 | tox -e docs-wiki -- -D confluence_space_name=${CONF_SPACE_NAME} -D confluence_parent_page=${CONF_PARENT_PAGE} -D confluence_server_user=${CONF_SERVER_USER} -D confluence_server_pass=${CONF_SERVER_PASS} -------------------------------------------------------------------------------- /tests/assets/no_include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | provision: 9 | 10 | orchestrate: 11 | 12 | execute: 13 | 14 | report: 15 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/list_block_devices.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: run playbook to list out local devices 3 | hosts: localhost 4 | 5 | tasks: 6 | - name: list out the local blk devices 7 | shell: lsblk 8 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/test_playbook_tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: run playbook to list out local devices 3 | hosts: localhost 4 | 5 | tasks: 6 | - name: list out the local blk devices 7 | shell: lsblk 8 | -------------------------------------------------------------------------------- /teflo/notifiers/ext/email/templates/email_on_start_txt_template.jinja: -------------------------------------------------------------------------------- 1 | Hello All, 2 | 3 | This is a Teflo Notification. 4 | 5 | Teflo scenario, {{ scenario.name }}, has started the following task: 6 | 7 | {{ passed_tasks }} -------------------------------------------------------------------------------- /tests/assets/correct_include_descriptor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | - ../assets/common.yml 10 | 11 | execute: 12 | 13 | report: 14 | -------------------------------------------------------------------------------- /tests/localhost_scenario/teflo.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | log_level=debug 3 | workspace=. 4 | data_folder=.teflo 5 | var_file=variable.yml 6 | ansible_extra_vars_files=true 7 | 8 | 9 | [orchestrator:ansible] 10 | verbosity=vv 11 | 12 | -------------------------------------------------------------------------------- /tests/assets/wrong_include_descriptor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | - cdf.yml 10 | 11 | provision: 12 | 13 | orchestrate: 14 | 15 | execute: 16 | 17 | report: 18 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking = False 3 | retry_files_enabled = False 4 | roles_path = ./.teflo/.roles:./ansible/roles 5 | log_filter = paramiko,pykwalify,teflo,blaster,urllib3 6 | log_path = ./ansible.log 7 | gather_timeout = 25 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Ryan Williams 2 | Stephen Matula 3 | Tiago M. Vieira 4 | Vimal Patel 5 | 6 | Rujuta Shinde 7 | Junqi Zhang 8 | Danny Baez -------------------------------------------------------------------------------- /tests/assets/empty_include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | - ' ' 10 | 11 | provision: 12 | 13 | orchestrate: 14 | 15 | execute: 16 | 17 | report: 18 | 19 | notifications: 20 | 21 | -------------------------------------------------------------------------------- /tests/assets/testvault.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | log_level = debug 3 | data_folder = /tLKJ 4 | workspace = /tmp/ws 5 | inventory_folder = /tmp 6 | CREDENTIAL_PATH=../assets/credentials_test.key 7 | VAULTPASS=teflo 8 | 9 | [orchestrator:ansible] 10 | log_remove = False 11 | verbosity = v -------------------------------------------------------------------------------- /tests/assets/wrong_include_sdf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | - ../assets/missing_colon_sdf.yml 10 | 11 | provision: 12 | 13 | orchestrate: 14 | 15 | execute: 16 | 17 | report: 18 | -------------------------------------------------------------------------------- /tests/localhost_scenario/scripts/hello_world.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | if len(sys.argv) == 2: 5 | print('Hello World to %s ! Testing local script executing using teflo' % sys.argv[1]) 6 | else: 7 | print ('Hello World ! Testing local script executing using teflo') 8 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf1_test_jinja.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf1 3 | description: "Included scenario" 4 | 5 | provision: 6 | - name: sdf1host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf2_test_jinja.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf2 3 | description: "Included scenario" 4 | 5 | provision: 6 | - name: sdf2host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | -------------------------------------------------------------------------------- /tests/assets/artifacts/host03/sample1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/localhost_scenario/scripts/cleanup_artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Cleaning up the data-passthrough artifact from the artifact executes tests." 4 | echo $PWD 5 | rm -r ${PWD}/sample_artifacts/SampleTest_*.xml 6 | rm -r ${PWD}/sample_artifacts/SampleDummy* 7 | ls -lrta ${PWD}/sample_artifacts/ 8 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf4_test_jinja.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf4 3 | description: "Included scenario" 4 | 5 | provision: 6 | - name: sdf4host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.3.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: detect-private-key 7 | - repo: https://github.com/zricethezav/gitleaks 8 | rev: v8.13.0 9 | hooks: 10 | - id: gitleaks -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/tests/test_execute_playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: run playbook to execute test script 3 | hosts: '{{ hosts }}' 4 | 5 | tasks: 6 | - name: execute test script 7 | shell: "bash add_two_numbers.sh X='{{ X }}' Y='{{ Y }}'" 8 | args: 9 | chdir: '{{ ch_dir }}' 10 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/template_host_test_playbook_tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: run playbook to list out local devices 3 | hosts: '{{ hosts }}' 4 | 5 | tasks: 6 | - name: list out the local blk devices 7 | shell: lsblk 8 | 9 | - name: print dummy host ip address 10 | shell: "echo {{ ip }}" 11 | -------------------------------------------------------------------------------- /docs/developers/index.rst: -------------------------------------------------------------------------------- 1 | Developer's Guide 2 | ----------------- 3 | 4 | Architecture Details 5 | ~~~~~~~~~~~~~~~~~~~~ 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | architecture 11 | 12 | Development Information 13 | ~~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | development 19 | -------------------------------------------------------------------------------- /tests/assets/artifacts/host03/sample2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf10.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf10 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf10host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf13.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf13 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf13host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf5 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf5host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | -------------------------------------------------------------------------------- /tests/assets/show_vars_data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Test -vars-data for show command 3 | description: "Test -vars-data for show command" 4 | provision: 5 | - name: "{{ var + '-hello' }}" 6 | groups: local 7 | ip_address: 127.0.0.1 8 | ansible_params: 9 | ansible_connection: local 10 | labels: ['hello1','hello2'] 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Distribution / packaging 6 | build/ 7 | dist/ 8 | *.egg-info/ 9 | 10 | # IDEs 11 | .idea 12 | .vscode 13 | 14 | # Sphix documentation 15 | docs/_build/ 16 | 17 | # Unit tests / coverage 18 | coverage/ 19 | *.coverage 20 | .tox/ 21 | .teflo/ 22 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf3 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf3host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf4 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf4host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf6.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf6 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf6host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf9.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf9 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf9host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf11.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf11 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf11host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: sdf 4 | description: "scenario for testing" 5 | provision: 6 | - name: {{ firstkey | default('test') }} 7 | provisioner: openstack 8 | ip_address: 127.0.0.1 9 | 10 | - name: {{ secondkey | default('test') }} 11 | provisioner: openstack 12 | ip_address: 127.0.0.1 13 | -------------------------------------------------------------------------------- /tests/assets/single_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | 10 | provision: 11 | - name: {{ asset_name | default('test') }} 12 | provisioner: openstack 13 | 14 | orchestrate: 15 | 16 | execute: 17 | 18 | report: 19 | 20 | notifications: 21 | 22 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf12.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf12 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | provision: 6 | - name: sdf12host 7 | groups: local 8 | ip_address: 127.0.0.1 9 | ansible_params: 10 | ansible_connection: local 11 | labels: ['hello1','hello2'] 12 | 13 | passed_tasks: ['provision', 'execute'] -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | coverage==7.2.3 2 | bumpversion==0.6.0 3 | git-review==2.3.1 4 | mock==5.0.1 5 | pycodestyle==2.10.0 6 | pytest==7.2.2 7 | #locking pytest-cov due to a regression with 2.8.0 8 | pytest-cov==2.7.1 9 | Sphinx==6.1.3 10 | sphinx-rtd-theme==0.5.1 11 | tox==4.4.11 12 | sphinx_automodapi==0.14.1 13 | sphinxcontrib-confluencebuilder==1.1 14 | cryptography==40.0.1 15 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf7 3 | include: 4 | - sdf10.yml 5 | - sdf11.yml 6 | description: "Included scenario for py3 environment using linchpin" 7 | 8 | provision: 9 | - name: sdf7host 10 | groups: local 11 | ip_address: 127.0.0.1 12 | ansible_params: 13 | ansible_connection: local 14 | labels: ['hello1','hello2'] 15 | 16 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf0.yml: -------------------------------------------------------------------------------- 1 | --- 2 | include: 3 | - sdf1.yml 4 | - sdf7.yml 5 | - sdf2.yml 6 | 7 | name: sdf0 8 | description: "Included scenario for py3 environment using linchpin" 9 | provision: 10 | - name: sdf0host 11 | groups: local 12 | ip_address: 127.0.0.1 13 | ansible_params: 14 | ansible_connection: local 15 | labels: ['hello1','hello2'] 16 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | include: 3 | - sdf3.yml 4 | - sdf8.yml 5 | - sdf5.yml 6 | name: sdf1 7 | description: "Included scenario for py3 environment using linchpin" 8 | 9 | provision: 10 | - name: sdf1host 11 | groups: local 12 | ip_address: 127.0.0.1 13 | ansible_params: 14 | ansible_connection: local 15 | labels: ['hello1','hello2'] 16 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | include: 3 | - sdf4.yml 4 | - sdf9.yml 5 | - sdf6.yml 6 | name: sdf2 7 | description: "Included scenario for py3 environment using linchpin" 8 | 9 | provision: 10 | - name: sdf2host 11 | groups: local 12 | ip_address: 127.0.0.1 13 | ansible_params: 14 | ansible_connection: local 15 | labels: ['hello1','hello2'] 16 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sample_artifacts/SampleTest.log: -------------------------------------------------------------------------------- 1 | Running Junit Test Suite: SampleTest 2 | Number of tests to execute: 2 3 | 4 | Starting: testMessageNotEqual 5 | Finished: testMessageNotEqual 6 | Time : 8.0 7 | 8 | Starting: testMessage 9 | Finished: testMessage 10 | Time : 0.0 11 | 12 | Number of tests executed: 2 13 | Time: 14 14 | Successful: true ran 2 tests 15 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf3_test_jinja.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf3 3 | include: 4 | -{% if TEST_JINJA is defined and TEST_JINJA|length > 1%} sdf4_test_jinja.yml{% endif %} 5 | description: "Included scenario" 6 | 7 | provision: 8 | - name: sdf3host 9 | groups: local 10 | ip_address: 127.0.0.1 11 | ansible_params: 12 | ansible_connection: local 13 | labels: ['hello1','hello2'] 14 | 15 | -------------------------------------------------------------------------------- /tests/assets/scenario_graph_basic_test/sdf8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: sdf8 3 | description: "Included scenario for py3 environment using linchpin" 4 | 5 | include: 6 | - sdf12.yml 7 | - sdf13.yml 8 | 9 | provision: 10 | - name: sdf8host 11 | groups: local 12 | ip_address: 127.0.0.1 13 | ansible_params: 14 | ansible_connection: local 15 | labels: ['hello1','hello2'] 16 | 17 | failed_tasks: ['execute'] -------------------------------------------------------------------------------- /tests/localhost_scenario/scripts/add_two_numbers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for arg in "$@" 3 | do 4 | index=$(echo $arg | cut -f1 -d=) 5 | val=$(echo $arg | cut -f2 -d=) 6 | case $index in 7 | X) x=$val;; 8 | 9 | Y) y=$val;; 10 | 11 | *) 12 | esac 13 | done 14 | ((result=x+y)) 15 | if [ $result -ne 30 ]; then 16 | echo "warning: result is not equal to 30." 17 | exit 2 18 | else 19 | echo "X+Y=$result" 20 | exit 0 21 | fi 22 | -------------------------------------------------------------------------------- /tests/assets/missing_colon_sdf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: test missing colon 4 | description: 5 | 6 | provision 7 | - name: localhost 8 | groups: local 9 | ip_address: 127.0.0.1 10 | ansible_params: 11 | ansible_connection: local 12 | 13 | execute: 14 | - name: run test 15 | description: "Run test" 16 | executor: runner 17 | hosts: localhost 18 | shell: 19 | - command: "ls" 20 | chdir: /tmp 21 | -------------------------------------------------------------------------------- /tests/assets/wrong_space_sdf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: test unnecessary space 4 | description: 5 | 6 | provision: 7 | - name: localhost 8 | groups: local 9 | ip_address: 127.0.0.1 10 | ansible_params: 11 | ansible_connection: local 12 | 13 | execute: 14 | - name: run test 15 | description: "Run test" 16 | executor: runner 17 | hosts: localhost 18 | shell: 19 | - command: "ls" 20 | chdir: /tmp 21 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf0_test_jinja.yml: -------------------------------------------------------------------------------- 1 | --- 2 | include: 3 | - sdf1_test_jinja.yml 4 | - {% if TEST_JINJA is defined and TEST_JINJA|length > 1%}sdf3_test_jinja.yml{% endif %} 5 | - sdf2_test_jinja.yml 6 | 7 | name: sdf0 8 | description: "Root Scenario" 9 | provision: 10 | - name: sdf0host 11 | groups: local 12 | ip_address: 127.0.0.1 13 | ansible_params: 14 | ansible_connection: local 15 | labels: ['hello1','hello2'] 16 | -------------------------------------------------------------------------------- /docs/users/index.rst: -------------------------------------------------------------------------------- 1 | User's Guide 2 | ~~~~~~~~~~~~ 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | quickstart 8 | 9 | Detailed Information 10 | ~~~~~~~~~~~~~~~~~~~~ 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | 15 | scenario_descriptor 16 | data_pass_through 17 | 18 | .. toctree:: 19 | :maxdepth: 1 20 | 21 | output 22 | examples 23 | best_practices 24 | localhost 25 | variable_data 26 | resource_labels 27 | faqs 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_remotes2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | remote_workspace: 4 | - workspace_url: git@github.com:dno-github/ssh-remote-teflo-lib2.git 5 | alias_name: remote2 6 | 7 | include: 8 | - "remote2/sdf_remote.yml" 9 | 10 | name: remote_include_example2 11 | description: include remote sdf from git server 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | -------------------------------------------------------------------------------- /tests/localhost_scenario/s_test_gv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: group_vars test 3 | description: provision example using local host to validate group_vars 4 | 5 | provision: 6 | - name: ans_gv 7 | ip_address: 127.0.0.1 8 | ansible_params: 9 | ansible_connection: local 10 | 11 | orchestrate: 12 | - name: orc_task1 13 | description: "Print system information." 14 | orchestrator: ansible 15 | hosts: localhost 16 | ansible_playbook: 17 | name: ansible/test_echo_var.yml 18 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_library2.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | --- 3 | remote_workspace: 4 | - workspace_url: https://github.com/dno-github/remote-teflo-lib2.git 5 | alias_name: remote 6 | 7 | include: 8 | - "remote/sdf_remote.yml" 9 | 10 | name: sdf using remote include 11 | description: "Provision step" 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_remotes1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | remote_workspace: 4 | - workspace_url: git@github.com:dno-github/ssh-remote-teflo-lib1.git 5 | alias_name: remote1 6 | 7 | include: 8 | - "remote1/sdf_remote.yml" 9 | 10 | name: remote_include_example1 11 | description: include remote sdf from git server 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_remotes4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | remote_workspace: 4 | - workspace_url: git@github.com:dno-github/ssh-remote-teflo-lib4.git 5 | alias_name: remote4 6 | 7 | include: 8 | - "remote4/sdf_remote.yml" 9 | 10 | name: remote_include_example4 11 | description: include remote sdf from git server 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | -------------------------------------------------------------------------------- /tests/localhost_scenario/ansible/variable_test_playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: run playbook to list out local devices 3 | hosts: '{{ hosts }}' 4 | 5 | tasks: 6 | - name: list out the local blk devices 7 | shell: lsblk 8 | 9 | - name: print dummy host ip address 10 | shell: "echo {{ ip }}" 11 | 12 | - name: print user name 13 | shell: "echo {{ name }}" 14 | 15 | 16 | - name: get env vars 17 | shell: "echo {{ lookup('env', 'uname') }}, {{ lookup('env', 'project') }} " 18 | 19 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_library3.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | --- 3 | remote_workspace: 4 | - workspace_url: "https://github.com/dno-github/remote-teflo-lib3.git" 5 | alias_name: remote 6 | 7 | include: 8 | - "remote/sdf_remote.yml" 9 | 10 | name: sdf using remote include 11 | description: "Provision step" 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_library4.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | --- 3 | remote_workspace: 4 | - workspace_url: "https://github.com/dno-github/-remote-teflo-lib4.git" 5 | alias_name: remote 6 | 7 | include: 8 | - "remote/sdf_remote.yml" 9 | 10 | name: sdf using remote include 11 | description: "Provision step" 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_remotes3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | remote_workspace: 4 | - workspace_url: git@github.com:dno-github/ssh-remote-teflo-lib3.git 5 | alias_name: remote3 6 | 7 | include: 8 | - "remote3/sdf_remote.yml" 9 | 10 | name: remote_include_example3 11 | description: include remote sdf from git server 12 | 13 | provision: 14 | - name: from_local_parent 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/assets/schemas/schema_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # default openstack libcloud schema 3 | 4 | type: map 5 | allowempty: True 6 | mapping: 7 | key1: 8 | type: str 9 | required: False 10 | key2: 11 | type: seq 12 | required: False 13 | sequence: 14 | - type: str 15 | credential: 16 | required: False 17 | type: map 18 | mapping: 19 | user: 20 | type: str 21 | required: True 22 | password: 23 | type: str 24 | required: True 25 | 26 | -------------------------------------------------------------------------------- /tests/assets/multiple_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | 10 | provision: 11 | - name: {{ asset_name }}-{{ other_name }} 12 | provisioner: openstack 13 | 14 | - name: {{ list_var }} 15 | provisioner: openstack 16 | 17 | - name: {{ dict_var }} 18 | provisioner: openstack 19 | 20 | - name: {{ python_version }} 21 | provisioner: openstack 22 | 23 | orchestrate: 24 | 25 | execute: 26 | 27 | report: 28 | 29 | notifications: 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/bumptag.yml: -------------------------------------------------------------------------------- 1 | 2 | name: "Autobump tag on master branch and relese to pypi" 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - 'teflo/__init__.py' 10 | 11 | jobs: 12 | tag-new-versions: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 2 18 | - uses: salsify/action-detect-and-tag-new-version@v1 19 | with: 20 | version-command: | 21 | grep -o "'.*'" ./teflo/__init__.py | sed "s/'//g" | head -n 1 22 | -------------------------------------------------------------------------------- /docs/contents.rst.inc: -------------------------------------------------------------------------------- 1 | .. toctree:: 2 | :maxdepth: 2 3 | :caption: Installation & Configuration 4 | :hidden: 5 | 6 | users/install 7 | users/configuration 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Using Teflo 12 | :hidden: 13 | 14 | users/index 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | :caption: Teflo Development 19 | :hidden: 20 | 21 | developers/index 22 | 23 | .. toctree:: 24 | :maxdepth: 1 25 | :caption: References 26 | :hidden: 27 | 28 | glossary 29 | changelog 30 | contact 31 | -------------------------------------------------------------------------------- /docs/_static/theme_override.css: -------------------------------------------------------------------------------- 1 | /* http://rackerlabs.github.io/docs-rackspace/tools/rtd-tables.html */ 2 | /* https://github.com/rtfd/sphinx_rtd_theme/issues/117 */ 3 | 4 | /* override table width restrictions */ 5 | @media screen and (min-width: 767px) { 6 | 7 | .wy-table-responsive table td { 8 | /* !important prevents the common CSS stylesheets from overriding 9 | this as on RTD they are loaded after this stylesheet */ 10 | white-space: normal !important; 11 | } 12 | 13 | .wy-table-responsive { 14 | overflow: visible !important; 15 | } 16 | } -------------------------------------------------------------------------------- /tests/assets/remote_include.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | --- 3 | remote_workspace: 4 | - workspace_url: https://github.com/dno-github/remote-teflo-lib1.git 5 | alias_name: remote 6 | - workspace_url: https://github.com/dno-github/remote-teflo-lib1.git 7 | alias_name: remote2 8 | 9 | include: 10 | - "remote/sdf_remote.yml" 11 | 12 | name: sdf using remote include 13 | description: "Provision step" 14 | 15 | provision: 16 | - name: from_local_parent 17 | groups: localhost 18 | ip_address: 127.0.0.1 19 | ansible_params: 20 | ansible_connection: local 21 | 22 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sdf_library1.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | --- 3 | remote_workspace: 4 | - workspace_url: https://github.com/dno-github/remote-teflo-lib1.git 5 | alias_name: remote 6 | - workspace_url: https://github.com/dno-github/remote-teflo-lib1.git 7 | alias_name: remote2 8 | 9 | include: 10 | - "remote/sdf_remote.yml" 11 | 12 | name: sdf using remote include 13 | description: "Provision step" 14 | 15 | provision: 16 | - name: from_local_parent 17 | groups: localhost 18 | ip_address: 127.0.0.1 19 | ansible_params: 20 | ansible_connection: local 21 | 22 | -------------------------------------------------------------------------------- /tests/assets/descriptor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: descriptor 3 | description: descriptor 4 | 5 | credentials: 6 | - name: provider 7 | 8 | include: 9 | 10 | provision: 11 | 12 | orchestrate: 13 | 14 | execute: 15 | 16 | report: 17 | 18 | notifications: 19 | - name: test_note_01 20 | notifier: email-notifier 21 | to: jsmit@redhat.com 22 | from: qe-team@redhta.com 23 | subjet: test_01 24 | on_demand: true 25 | 26 | - name: test_note_02 27 | notifier: email-notifier 28 | to: jsmit@redhat.com 29 | from: qe-team@redhta.com 30 | subjet: test_02 31 | on_demand: true 32 | -------------------------------------------------------------------------------- /tests/assets/test_nested_var_file.yml: -------------------------------------------------------------------------------- 1 | # nested var file with str, list, dict 2 | --- 3 | asset_name: {{ nested_var }} 4 | nested_var: "teflo_test" 5 | devices: 6 | - /dev/vdc 7 | list_var: "{{ devices }}" 8 | languages: 9 | perl: Elite 10 | python: Elite 11 | pascal: Lame 12 | dict_var: "{{ languages }}" 13 | unused: "{{ ansible_facts.hostname }}" 14 | python: 15 | version: "3.10.0" 16 | python_version: "{{ python.version }}" 17 | osp_director_input_dir: "{{ lookup('config', 'COLLECTIONS_PATH', 'COLLECTIONS_PATHS', wantlist=True, on_missing='skip')[0][0] }}/ansible_collections/css/psi/tests/environments/{{ os_cloud }}/cloud/undercloud" 18 | -------------------------------------------------------------------------------- /tests/assets/credentials_test.key: -------------------------------------------------------------------------------- 1 | $ANSIBLE_VAULT;1.1;AES256 2 | 64633238366638316139373861376535373136646631643764303866343332396437626366363633 3 | 3739333236623865663333656266383136353239356331610a353764636433393335356539376532 4 | 32646639356161633062663930643435316139623764396432346666653938643936613437396366 5 | 6131363061373436610a633537383965613433336332643130303063613163643664303239656535 6 | 37313938313863353231376465333266383232653961373438643463313538343436363431353036 7 | 61333131316336613566663064336266643935393566383532643838663463326335623061393336 8 | 62313764613637393539326635376130633266393539646639346435343532313335646164336132 9 | 35613231643764623166 10 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = cbn 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /examples/docs-usage/teflo_example.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | log_level=debug 3 | workspace=. 4 | data_folder=.teflo 5 | # This is the directory for all downloaded remote workspaces 6 | remote_workspace_download_location=remote_dir 7 | # if you set this to False, the downloaded remote workspace 8 | # will not be removed after the teflo job is done. And teflo 9 | # will automatically reuse the downloaded workspace if you run 10 | # the same job again(skip the download process, could potentially 11 | # save your time) 12 | # when using SSH instead of HTTPS to clone remote workspace, private key path can be set from here. 13 | GIT_SSH_COMMAND=/home/user/keys/private_k 14 | CLEAN_CACHED_WORKSPACE_AFTER_EACH_RUN = False 15 | 16 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: docs/conf.py 11 | 12 | # Optionally build your docs in additional formats such as PDF and ePub 13 | formats: all 14 | 15 | # Optionally set the version of Python and requirements required to build your docs 16 | 17 | build: 18 | os: ubuntu-22.04 19 | tools: 20 | python: "3.9" 21 | 22 | python: 23 | install: 24 | - requirements: test-requirements.txt 25 | - method: pip 26 | path: . 27 | extra_requirements: 28 | - docs -------------------------------------------------------------------------------- /docs/link_mapping: -------------------------------------------------------------------------------- 1 | [webpages] 2 | quickstart.html=Teflo+Quickstart 3 | ../users/scenario_descriptor.html=Scenario+Descriptor 4 | ../../developers/architecture.html=Architecture 5 | ../developers/architecture.html=Architecture 6 | architecture.html=Architecture 7 | development.html=Development 8 | data_pass_through.html=Data+Pass-through 9 | best_practices.html=Best+Practices 10 | ../configuration.html=Configure+Teflo 11 | configuration.html=Configure+Teflo 12 | definitions/credentials.html=Credentials 13 | credentials.html=Credentials 14 | ../output.html=Teflo+Output 15 | output.html=Teflo+Output 16 | definitions/provision.html=Provision 17 | ../examples.html=Examples 18 | install.html=Install+Teflo 19 | orchestrate.html=Orchestrate 20 | definitions/report.html=Report 21 | report.html=Report 22 | -------------------------------------------------------------------------------- /docs/wiki-sanitizer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from configparser import SafeConfigParser 4 | import os 5 | 6 | docs_dir='.' 7 | parser = SafeConfigParser() 8 | parser.read('link_mapping') 9 | 10 | for dirName, subdirList, fileList in os.walk(os.path.abspath(docs_dir)): 11 | for name in fileList: 12 | if name.find('.rst') != -1: 13 | with open(os.path.join(dirName, name), 'r') as f: 14 | data = f.read() 15 | for k, v in parser.items('webpages'): 16 | if data.find(k) != -1: 17 | print("In file, %s, found %s. Replacing with %s" % (name, k, v)) 18 | data = data.replace(k, v) 19 | with open(os.path.join(dirName, name), 'w') as fd: 20 | fd.write(data) 21 | -------------------------------------------------------------------------------- /tests/assets/test_template_render.yml: -------------------------------------------------------------------------------- 1 | 2 | # -*- coding: utf-8 -*- 3 | --- 4 | include: 5 | - teflo/stack/provision_localhost.yml 6 | - teflo/stack/provision_libvirt.yml 7 | - {% if true %}teflo/stack/orchestrate-123.yml{% endif %} 8 | - teflo/stack/orchestrate.yml 9 | 10 | name: py3_include_provision 11 | description: "Provision step" 12 | 13 | provision: 14 | - name: local_host 15 | groups: localhost 16 | ip_address: 127.0.0.1 17 | ansible_params: 18 | ansible_connection: local 19 | 20 | 21 | orchestrate: 22 | - name: "{{ from_cmd_line }}" 23 | description: "Test teflo" 24 | orchestrator: ansible 25 | hosts: local_host 26 | ansible_playbook: 27 | name: playbook.yml 28 | ansible_options: 29 | extra_vars: 30 | hello: "{{ hello }}" 31 | 32 | 33 | -------------------------------------------------------------------------------- /teflo/executors/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | from .ansible_executor_plugin import AnsibleExecutorPlugin 19 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CHANGES LICENSE AUTHORS README.rst 2 | include teflo/files/schema.yml 3 | include teflo/files/extensions.py 4 | include teflo/provisioners/ext/bkr_client_plugin/schema.yml 5 | include teflo/provisioners/ext/os_libcloud_plugin/schema.yml 6 | include teflo/notifiers/ext/email/schema/schema.yml 7 | include teflo/notifiers/ext/email/schema/email_extensions.py 8 | include teflo/notifiers/ext/email/templates/email_on_start_txt_template.jinja 9 | include teflo/notifiers/ext/email/templates/email_txt_template.jinja 10 | recursive-include teflo/orchestrators/ext/ansible_orchestrator_plugin/files * 11 | recursive-include teflo/executors/ext/ansible_executor_plugin/files * 12 | exclude setup.cfg 13 | prune docs/_build 14 | prune docs/.ropeproject 15 | prune docs/.gitignore 16 | prune tests/.cache 17 | prune extensions 18 | prune .ropeproject 19 | prune .git 20 | prune .gitignore 21 | prune .idea 22 | -------------------------------------------------------------------------------- /teflo/orchestrators/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | 20 | from .ansible_orchestrator_plugin import AnsibleOrchestratorPlugin 21 | -------------------------------------------------------------------------------- /teflo/executors/ext/ansible_executor_plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from .ansible_executor_plugin import AnsibleExecutorPlugin 20 | -------------------------------------------------------------------------------- /teflo/provisioners/ext/bkr_client_plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from .beaker_client_plugin import BeakerClientProvisionerPlugin 20 | -------------------------------------------------------------------------------- /.github/workflows/pushtopypi.yml: -------------------------------------------------------------------------------- 1 | name: "Push the master branch to pypi when develop is merged to master and version is changed" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'teflo/__init__.py' 9 | 10 | jobs: 11 | deploy_pypi: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up Python 16 | uses: actions/setup-python@v1 17 | with: 18 | python-version: '3.x' 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade pip 22 | pip install setuptools wheel twine 23 | - name: Build and publish 24 | env: 25 | TWINE_USERNAME: ${{ secrets.PYPI_DNO_USERNAME }} 26 | TWINE_PASSWORD: ${{ secrets.PYPI_DNO_PASSWORD }} 27 | run: | 28 | python setup.py sdist bdist_wheel 29 | twine upload dist/* 30 | -------------------------------------------------------------------------------- /teflo/provisioners/ext/os_libcloud_plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from .openstack_libcloud_plugin import OpenstackLibCloudProvisionerPlugin 20 | -------------------------------------------------------------------------------- /teflo/orchestrators/ext/ansible_orchestrator_plugin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from .ansible_orchestrator_plugin import AnsibleOrchestratorPlugin 20 | -------------------------------------------------------------------------------- /teflo/provisioners/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from .os_libcloud_plugin import OpenstackLibCloudProvisionerPlugin 20 | from .bkr_client_plugin import BeakerClientProvisionerPlugin 21 | -------------------------------------------------------------------------------- /teflo/executors/__init__.py: -------------------------------------------------------------------------------- 1 | # This program is free software: you can redistribute it and/or modify 2 | # it under the terms of the GNU General Public License as published by 3 | # the Free Software Foundation, either version 3 of the License, or 4 | # (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License 12 | # along with this program. If not, see . 13 | # 14 | 15 | """ 16 | teflo.executors 17 | 18 | Package containing teflo executor modules. 19 | 20 | :copyright: (c) 2022 Red Hat, Inc. 21 | :license: GPLv3, see LICENSE for more details. 22 | """ 23 | from .execute_manager import ExecuteManager 24 | -------------------------------------------------------------------------------- /teflo/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.utils 20 | 21 | Utils package contains utility like modules. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | -------------------------------------------------------------------------------- /teflo/static/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.static 20 | 21 | Static package containing static like modules. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | -------------------------------------------------------------------------------- /teflo/notifiers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.notifiers 21 | 22 | Teflo's default notifier. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from .notification_emitter import Notifier 29 | -------------------------------------------------------------------------------- /teflo/notifiers/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.notifiers.email 21 | 22 | Teflo's default email notifier. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from .email import EmailNotificationPlugin 29 | -------------------------------------------------------------------------------- /teflo/importers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.importers 21 | 22 | Package containing teflo importer module. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from .artifact_importer import ArtifactImporter 29 | -------------------------------------------------------------------------------- /teflo/provisioners/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.provisioners 21 | 22 | Package containing teflo provisioner modules. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | from .asset_provisioner import AssetProvisioner 28 | -------------------------------------------------------------------------------- /teflo/notifiers/ext/email/schema/schema.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # default email notifier schema 3 | 4 | type: map 5 | allowempty: True 6 | func: valid_email_combos 7 | mapping: 8 | to: 9 | required: True 10 | type: seq 11 | sequence: 12 | - type: str 13 | from: 14 | required: True 15 | type: str 16 | subject: 17 | required: False 18 | type: str 19 | cc: 20 | required: False 21 | type: seq 22 | sequence: 23 | - type: str 24 | attachments: 25 | required: False 26 | type: seq 27 | sequence: 28 | - type: str 29 | signature_file: 30 | required: False 31 | type: str 32 | message_body: 33 | required: False 34 | type: str 35 | message_template: 36 | required: False 37 | type: str 38 | credential: 39 | type: map 40 | allowempty: True 41 | mapping: 42 | smtp_host: 43 | required: True 44 | smtp_port: 45 | required: False 46 | smtp_user: 47 | required: False 48 | smtp_password: 49 | required: False 50 | smtp_starttls: 51 | required: False -------------------------------------------------------------------------------- /teflo/orchestrators/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.orchestrators 21 | 22 | Package containing teflo orchestrator modules. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from .action_orchestrator import ActionOrchestrator 29 | -------------------------------------------------------------------------------- /teflo/notifiers/ext/email/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.notifiers.email 21 | 22 | Teflo's default email notifier. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from .email_notification_plugin import EmailNotificationPlugin 29 | -------------------------------------------------------------------------------- /teflo/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo 20 | 21 | A framework that cares about product interoperability quality. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from .teflo import Teflo 27 | __version__ = '2.4.1' 28 | __author__ = 'Red Hat Inc.' 29 | -------------------------------------------------------------------------------- /teflo/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.providers 21 | 22 | Package containing teflo provider modules. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from .beaker import BeakerProvider 29 | from .openstack import OpenstackProvider 30 | from .libvirt import LibvirtProvider 31 | from .aws import AwsProvider 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-tests clean docs 2 | 3 | all: clean-pyc clean-tests clean test-functional docs 4 | 5 | clean-all: clean-pyc clean-tests clean 6 | 7 | test-all: test-functional test-scenario 8 | 9 | test-functional: 10 | tox -e py3-unit 11 | 12 | test-scenario: 13 | tox -e py3-scenario 14 | 15 | clean: 16 | rm -rf *.egg 17 | rm -rf *.egg-info 18 | rm -rf docs/_build 19 | rm -rf docs/.examples 20 | rm -rf .cache 21 | rm -rf .tox 22 | rm -rf build 23 | rm -rf dist 24 | 25 | clean-tests: 26 | rm -rf tests/.coverage* 27 | rm -rf tests/.cache 28 | rm -rf tests/coverage 29 | rm -rf tests/localhost_scenario/.teflo 30 | rm -rf tests/localhost_scenario/.ansible 31 | rm -rf tests/functional/coverage 32 | rm -rf tests/functional/.ansible 33 | rm -rf tests/functional/.coverage* 34 | 35 | clean-pyc: 36 | find . -name '*.pyc' -exec rm -f {} + 37 | find . -name '*.pyo' -exec rm -f {} + 38 | find . -name '*~' -exec rm -f {} + 39 | 40 | docs: 41 | tox -e docs 42 | 43 | docs-wiki: 44 | ./shell_tox.sh 45 | 46 | bump-major: 47 | bumpversion major --commit 48 | 49 | bump-minor: 50 | bumpversion minor --commit 51 | 52 | bump-patch: 53 | bumpversion patch --commit 54 | -------------------------------------------------------------------------------- /teflo/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.resources 20 | 21 | Package containing teflo resource modules. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | from .actions import Action 28 | from .executes import Execute 29 | from .assets import Asset 30 | from .reports import Report 31 | from .scenario import Scenario 32 | from .notification import Notification 33 | -------------------------------------------------------------------------------- /examples/docs-usage/resource_check.yml: -------------------------------------------------------------------------------- 1 | # example 1 2 | --- 3 | name: Example Discriptor 4 | description: Descriptor file with resource check section 5 | 6 | resource_check: 7 | monitored_services: 8 | - polarion 9 | - umb 10 | playbook: 11 | - name: ansible/list_block_devices.yml 12 | ansible_options: 13 | extra_vars: 14 | X: 18 15 | Y: 12 16 | ch_dir: ./scripts/ 17 | - name: ansible/tests/test_execute_playbook.yml 18 | ansible_options: 19 | extra_vars: 20 | X: 12 21 | Y: 12 22 | ch_dir: ../../scripts/ 23 | script: 24 | - name: ./scripts/hello_world1.py Teflo_user 25 | executable: python 26 | - name: ./scripts/add_two_numbers.sh X=15 Y=15 27 | 28 | 29 | provision: 30 | . 31 | . 32 | . 33 | 34 | orchestrate: 35 | . 36 | . 37 | . 38 | 39 | execute: 40 | . 41 | . 42 | . 43 | 44 | # example 2 45 | --- 46 | name: Example Discriptor 47 | description: Descriptor file with resource check section 48 | 49 | resource_check: 50 | monitored_services: ['polarion', 'umb'] 51 | 52 | provision: 53 | . 54 | . 55 | . 56 | 57 | orchestrate: 58 | . 59 | . 60 | . 61 | 62 | execute: 63 | . 64 | . 65 | . 66 | 67 | -------------------------------------------------------------------------------- /tests/localhost_scenario/sample_artifacts/SampleTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/contact.rst: -------------------------------------------------------------------------------- 1 | Contacts 2 | ======== 3 | 4 | The Teflo Tool 5 | --------------- 6 | 7 | Framework Community 8 | ~~~~~~~~~~~~~~~~~~~ 9 | 10 | Information on framework updates can be found on the carbon-watchers list. If you have any questions, need help 11 | developing your scenarios, or how best to use teflo to fit your use case, we encourage you to reach out to the 12 | carbon-watchers list as we have a diverse community of users that can offer insight on some of these 13 | questions. 14 | 15 | Please subscribe `here `__. 16 | 17 | (WIP) Logging Issues with Teflo 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | Please log the issue on github `here `__ 20 | 21 | .. note:: 22 | This section is still WIP, this space will be updated with more info on what additional 23 | info can be included in the github issue for correct tracking. 24 | 25 | Authors and Maintainers 26 | ----------------------- 27 | 28 | Please feel free to reach out to any of the maintainers, if you have 29 | any questions. 30 | 31 | Maintainers 32 | ~~~~~~~~~~~ 33 | .. literalinclude:: ../AUTHORS 34 | :lines: 6-7 35 | 36 | Creators 37 | ~~~~~~~~ 38 | .. literalinclude:: ../AUTHORS 39 | :lines: 1-4 40 | -------------------------------------------------------------------------------- /teflo/tasks/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks 20 | 21 | Package containing teflo task modules. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | from .cleanup import CleanupTask 28 | from .execute import ExecuteTask 29 | from .orchestrate import OrchestrateTask 30 | from .provision import ProvisionTask 31 | from .report import ReportTask 32 | from .validate import ValidateTask 33 | from .notification import NotificationTask 34 | -------------------------------------------------------------------------------- /tests/assets/teflo.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | log_level = debug 3 | data_folder = /tmp 4 | workspace = /tmp/ws 5 | inventory_folder = /tmp 6 | var_file = ../assets/vars_data.yml 7 | included_sdf_iterate_method = by_depth 8 | collections_paths = ./collections/ 9 | 10 | [credentials:email] 11 | smtp_host = {{ TEFLO_EMAIL_SERVER | default('smtp.dummy.server.com') }} 12 | smtp_port = 33 13 | smtp_user = jones 14 | smtp_password = ChangeMe 15 | smtp_starttls = True 16 | 17 | [credentials:beaker] 18 | hub_url = null 19 | keytab = null 20 | keytab_principal = null 21 | 22 | [credentials:openstack] 23 | auth_url = null 24 | tenant_name = null 25 | username = null 26 | password = null 27 | 28 | [credentials:libvirt-creds] 29 | create_creds = False 30 | 31 | [credentials:polarion] 32 | polarion_url = null 33 | username = null 34 | password = null 35 | 36 | [orchestrator:ansible] 37 | log_remove = False 38 | verbosity = v 39 | 40 | [task_concurrency] 41 | provision = False 42 | report = False 43 | 44 | [feature_toggles:host] 45 | plugin_implementation = False 46 | 47 | [timeout] 48 | provision = 25 49 | orchestrate = 25 50 | cleanup = 25 51 | report = 25 52 | execute = 25 53 | 54 | [alias] 55 | dev_run = run -s ../assets/single_template.yml -t validate -d /tmp 56 | prod_run = rshow -s scenario.yml --list-labels 57 | 58 | -------------------------------------------------------------------------------- /teflo/provisioners/ext/os_libcloud_plugin/schema.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # default openstack libcloud schema 3 | 4 | type: map 5 | allowempty: True 6 | mapping: 7 | image: 8 | required: True 9 | type: str 10 | flavor: 11 | required: True 12 | type: str 13 | networks: 14 | required: True 15 | type: seq 16 | sequence: 17 | - type: str 18 | floating_ip_pool: 19 | required: False 20 | type: str 21 | keypair: 22 | required: False 23 | type: str 24 | server_metadata: 25 | required: False 26 | type: map 27 | allowempty: True 28 | mapping: 29 | regex;(.*): 30 | required: False 31 | type: any 32 | credential: 33 | required: False 34 | type: map 35 | mapping: 36 | auth_url: 37 | type: str 38 | required: True 39 | username: 40 | type: str 41 | required: True 42 | password: 43 | type: str 44 | required: True 45 | tenant_name: 46 | type: str 47 | required: True 48 | domain_name: 49 | type: str 50 | required: False 51 | region: 52 | type: str 53 | required: False 54 | project_id: 55 | type: str 56 | required: False 57 | project_domain_id: 58 | type: str 59 | required: False 60 | -------------------------------------------------------------------------------- /teflo/orchestrators/ext/ansible_orchestrator_plugin/files/schema.yml: -------------------------------------------------------------------------------- 1 | # default schema for ansible orchestrator 2 | 3 | type: map 4 | allowempty: True 5 | func: valid_action_types 6 | mapping: 7 | ansible_playbook: 8 | allowempty: True 9 | type: map 10 | mapping: 11 | name: 12 | type: str 13 | required: True 14 | ansible_script: 15 | allowempty: True 16 | func: valid_ansible_script_type 17 | type: map 18 | mapping: 19 | name: 20 | type: str 21 | required: True 22 | ansible_shell: 23 | allowempty: True 24 | type: seq 25 | sequence: 26 | - type: map 27 | mapping: 28 | command: 29 | type: str 30 | required: True 31 | chdir: 32 | type: str 33 | creates: 34 | type: str 35 | decrypt: 36 | type: str 37 | executable: 38 | type: str 39 | removes: 40 | type: str 41 | warn: 42 | type: str 43 | stdin: 44 | type: str 45 | stdin_add_newline: 46 | type: str 47 | ansible_options: 48 | allowempty: True 49 | type: map 50 | ansible_galaxy_options: 51 | allowempty: True 52 | type: map 53 | environment_vars: 54 | allowempty: True 55 | type: map 56 | -------------------------------------------------------------------------------- /tests/functional/test_misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_misc 21 | 22 | Unit tests for testing misc code. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from teflo._compat import string_types 29 | from teflo.static.playbooks import GIT_CLONE_PLAYBOOK, SYNCHRONIZE_PLAYBOOK 30 | 31 | 32 | def test_import_synchronize_pb(): 33 | assert isinstance(SYNCHRONIZE_PLAYBOOK, string_types) 34 | 35 | 36 | def test_import_git_clone_pb(): 37 | assert isinstance(GIT_CLONE_PLAYBOOK, string_types) 38 | -------------------------------------------------------------------------------- /teflo/notifiers/ext/email/schema/email_extensions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | Pykwalify extensions module for email plugin. 20 | 21 | Module containing custom validation functions used for schema checking. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | 28 | def valid_email_combos(value, rule_obj, path): 29 | """Verify valid combinations of email parameters.""" 30 | if set(['message_template', 'message_body']).issubset(value.keys()): 31 | raise AssertionError('Message_body and message_template are mutually exclusive.') 32 | 33 | return True 34 | -------------------------------------------------------------------------------- /teflo/provisioners/ext/bkr_client_plugin/extensions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | Pykwalify extensions module for beaker client plugin 20 | 21 | Module containing custom validation functions used for beaker client schema checking. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | import os 28 | 29 | 30 | def valid_file_exist(value, rule_obj, path): 31 | """ Verify if the given file exist.""" 32 | 33 | if os.path.exists(value): 34 | return True 35 | else: 36 | raise AssertionError( 37 | '%s must be an existing file! Cannot find file: %s.' % (path.split('/')[-1], value) 38 | ) 39 | -------------------------------------------------------------------------------- /examples/docs-usage/resource_labels.yml: -------------------------------------------------------------------------------- 1 | --- 2 | provision: 3 | - name: db2_ci_test_client_a 4 | groups: client 5 | provisioner: openstack-libcloud 6 | provider: 7 | name: openstack 8 | credential: openstack 9 | image: rhel-7.5-server-x86_64-released 10 | flavor: m1.small 11 | networks: 12 | - {{ OS_NETWORK }} 13 | keypair: {{ OS_KEYPAIR }} 14 | ansible_params: 15 | ansible_user: cloud-user 16 | ansible_ssh_private_key_file: keys/{{ OS_KEYPAIR }} 17 | labels: prod_a 18 | 19 | - name: laptop 20 | groups: localhost 21 | ip_address: 127.0.0.1 22 | ansible_params: 23 | ansible_connection: local 24 | labels: abc, prod_b 25 | 26 | - name: laptop1 27 | groups: localhost 28 | ip_address: 127.0.0.1 29 | ansible_params: 30 | ansible_connection: local 31 | labels: 32 | - pqr 33 | - lmn 34 | 35 | orchestrate: 36 | - name: ansible/install-certs.yml 37 | description: "install internal certificates" 38 | orchestrator: ansible 39 | hosts: client 40 | ansible_galaxy_options: 41 | role_file: roles.yml 42 | labels: prod_a1 43 | 44 | - name: ansible/junit-install.yml 45 | description: "install junit framework on test clients" 46 | orchestrator: ansible 47 | hosts: laptop 48 | ansible_galaxy_options: 49 | role_file: roles.yml 50 | labels: prod_b 51 | 52 | 53 | 54 | - name: ansible/install-certs.yml 55 | description: "install internal certificates" 56 | orchestrator: ansible 57 | hosts: laptop 58 | ansible_galaxy_options: 59 | role_file: roles.yml 60 | labels: prod_b -------------------------------------------------------------------------------- /tests/assets/artifacts/host03/sample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Error 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/functional/test_ansible_vault.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_ansible_vault 21 | 22 | Unit tests for testing teflo asset provisioner class. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | import mock 29 | import pytest 30 | import os 31 | from teflo._compat import ConfigParser 32 | from teflo.utils.config import Config 33 | 34 | @pytest.fixture(scope='class') 35 | def test_vault_config(): 36 | config_file = '../assets/testvault.cfg' 37 | config = Config() 38 | os.environ['TEFLO_SETTINGS'] = config_file 39 | config.load() 40 | return config 41 | 42 | @pytest.fixture 43 | def creds_expected(): 44 | return [{'hub_url': 'null', 'keytab': 'null', 'keytab_principal': 'null', 'name': 'beaker'}] 45 | 46 | class TestAnsibleVault(object): 47 | 48 | @staticmethod 49 | def test_ansible_vault_from_cfg(test_vault_config, creds_expected): 50 | assert test_vault_config.get("CREDENTIALS") == creds_expected -------------------------------------------------------------------------------- /.github/workflows/run_unit_tests.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: PR_unit_tests 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the develop branch 7 | on: 8 | pull_request: 9 | branches: [ develop ] 10 | 11 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 12 | jobs: 13 | # This workflow contains a single job called "build" 14 | build: 15 | # The type of runner that the job will run on 16 | runs-on: ubuntu-latest 17 | container: ${{ matrix.container }} 18 | strategy: 19 | matrix: 20 | container: 21 | - 'quay.io/centos/centos:stream9' 22 | fail-fast: false 23 | 24 | # Steps represent a sequence of tasks that will be executed as part of the job 25 | steps: 26 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 27 | - uses: actions/checkout@v3 28 | - run: cat /etc/os-release 29 | 30 | # Runs a single command using the runners shell 31 | - name: install required packages 32 | run: | 33 | dnf install -y glibc-langpack-en gcc python3 python3-devel python3-pip krb5-workstation krb5-devel git --nogpgcheck 34 | 35 | # - name: update locale 36 | # run: localectl set-locale LANG=en_US.utf8 37 | 38 | - name: install pip virtualenv and tox 39 | env: 40 | LANG: en_US.UTF-8 41 | LC_ALL: en_US.UTF-8 42 | run: pip3 install virtualenv tox 43 | 44 | # Runs a set of commands using the runners shell 45 | - name: Run functional unit tests 46 | env: 47 | LANG: en_US.UTF-8 48 | LC_ALL: en_US.UTF-8 49 | run: tox -e py3-unit 50 | 51 | # Runs a set of commands using the runners shell 52 | - name: Run local scenario unit test 53 | env: 54 | LANG: en_US.UTF-8 55 | LC_ALL: en_US.UTF-8 56 | run: tox -e py3-scenario 57 | -------------------------------------------------------------------------------- /teflo/tasks/validate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.validate 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | 28 | 29 | class ValidateTask(TefloTask): 30 | """Validate task.""" 31 | __task_name__ = 'validate' 32 | 33 | def __init__(self, resource, **kwargs): 34 | """Constructor. 35 | 36 | :param resource: resource reference 37 | :type resource: object 38 | :param kwargs: additional keyword arguments 39 | :type kwargs: dict 40 | """ 41 | super(ValidateTask, self).__init__(**kwargs) 42 | self.resource = resource 43 | 44 | def run(self): 45 | """Run. 46 | 47 | This method is the main entry point to the task. 48 | """ 49 | self.logger.info( 50 | 'Validating %s (%s)', self.resource.__class__, self.resource.name 51 | ) 52 | try: 53 | # validate the given resource 54 | self.resource.validate() 55 | except Exception: 56 | self.logger.error('Failed to validate %s' % self.resource.name) 57 | stackmsg = self.get_formatted_traceback() 58 | self.logger.error(stackmsg) 59 | raise 60 | -------------------------------------------------------------------------------- /tests/functional/test_config_class.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_config_class 21 | 22 | Unit tests for testing teflo config class. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | import copy 29 | import os 30 | import mock 31 | 32 | import pytest 33 | 34 | from teflo.utils.config import Config 35 | 36 | 37 | @pytest.fixture(scope='class') 38 | def config(): 39 | return Config() 40 | 41 | 42 | class TestConfig(object): 43 | @staticmethod 44 | def test_del_parser(config): 45 | with pytest.raises(AttributeError): 46 | dummy_config = copy.copy(config) 47 | dummy_config.__del_parser__() 48 | print(dummy_config.parser) 49 | 50 | @staticmethod 51 | def test_load_missing_config(config): 52 | config.load() 53 | 54 | @staticmethod 55 | def test_load_config_by_env_var(config): 56 | os.environ['TEFLO_SETTINGS'] = '../assets/teflo.cfg' 57 | config.load() 58 | 59 | @staticmethod 60 | def test_load_config_jinja_template(config): 61 | os.environ['TEFLO_SETTINGS'] = '../assets/teflo.cfg' 62 | os.environ['TEFLO_EMAIL_SERVER'] = 'smtp.teflo.server.com' 63 | config.load() 64 | assert 'smtp.teflo.server.com' in config.parser.get('credentials:email', 'smtp_host') 65 | 66 | -------------------------------------------------------------------------------- /docs/users/localhost.rst: -------------------------------------------------------------------------------- 1 | Using Localhost 2 | =============== 3 | 4 | There may be a scenario where you want to run cmds or scripts on the 5 | local system instead of the provisioned resources. There are couple options 6 | to be able to do this. 7 | 8 | Explicit Localhost 9 | ------------------ 10 | 11 | The following is an example of a statically defined local machine: 12 | 13 | .. _localhost_example: 14 | 15 | Example 16 | +++++++ 17 | 18 | .. literalinclude:: ../../examples/docs-usage/orchestrate.yml 19 | :lines: 331-363 20 | 21 | When explicitly defined, this host entry is written to the master inventory 22 | file and the localhost will be accessible to ALL the Orchestrate and Execute tasks 23 | in the scenario. 24 | 25 | Implicit Localhost 26 | ------------------ 27 | 28 | As of 1.6.0, The use of any other arbitrary hostname will not be supported to infer localhost. 29 | It must be *localhost* that is used as a value to *hosts* in the Orchestrate or Execute sections, 30 | Teflo will infer that the intended task is to be run on the localhost. 31 | 32 | Example 33 | +++++++ 34 | 35 | Here an Orchestrate and an Execute task refer to *localhost*, 36 | respectively, that are not defined in the provision section. 37 | 38 | .. code-block:: yaml 39 | 40 | --- 41 | provision: 42 | - name: ci_test_client_b 43 | groups: 44 | - client 45 | - vnc 46 | ip_address: 192.168.100.51 47 | ansible_params: 48 | ansible_private_ssh_key: keys/test_key 49 | 50 | orchestrate: 51 | - name: test_setup_playbook.yml 52 | description: "running a test setup playbook on localhost" 53 | orchestrator: ansible 54 | hosts: localhost 55 | 56 | execute: 57 | - name: test execution 58 | description: "execute some test script locally" 59 | hosts: localhost 60 | executor: runner 61 | ignore_rc: False 62 | shell: 63 | - chdir: /home/user/tests 64 | command: python test_sample.py --output-results suite_results.xml 65 | ignore_rc: True 66 | artifacts: 67 | - /home/user/tests/suite_results.xml 68 | 69 | -------------------------------------------------------------------------------- /teflo/tasks/notification.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.notification 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | from ..notifiers import Notifier 28 | 29 | 30 | class NotificationTask(TefloTask): 31 | """Notification task.""" 32 | __task_name__ = 'notify' 33 | 34 | def __init__(self, msg, resource, **kwargs): 35 | """Constructor. 36 | 37 | :param resource: resource reference 38 | :type resource: object 39 | :param kwargs: additional keyword arguments 40 | :type kwargs: dict 41 | """ 42 | super(NotificationTask, self).__init__(**kwargs) 43 | self.msg = msg 44 | self.resource = resource 45 | self.notifier = Notifier(resource) 46 | 47 | def run(self): 48 | """Run. 49 | 50 | This method is the main entry point to the task. 51 | """ 52 | 53 | try: 54 | # validate the given resource 55 | self.logger.info(self.msg) 56 | self.notifier.notify() 57 | except Exception: 58 | self.logger.error('Notification failed.') 59 | stackmsg = self.get_formatted_traceback() 60 | self.logger.error(stackmsg) 61 | raise 62 | -------------------------------------------------------------------------------- /teflo/notifiers/ext/email/templates/email_txt_template.jinja: -------------------------------------------------------------------------------- 1 | Hello All, 2 | 3 | This is a Teflo Notification. 4 | 5 | Teflo has completed executing the scenario, {{ scenario.name }}, with overall status: 6 | 7 | {% if scenario.overall_status == 0 %} 8 | Passed 9 | {% else %} 10 | Failed 11 | {% endif %} 12 | 13 | {% if not passed_tasks and not failed_tasks %} 14 | No tasks were executed. 15 | {% else %} 16 | The following tasks have completed: 17 | {% if passed_tasks %} 18 | Passed: {{ passed_tasks }} 19 | {% endif %} 20 | {% if failed_tasks %} 21 | Failed: {{ failed_tasks }} 22 | {% endif %} 23 | {% endif %} 24 | 25 | {% if scenario.get_executes() %} 26 | {% for execute in scenario.get_executes() %} 27 | {% if execute.artifact_locations %} 28 | Collected the following artifacts: 29 | {% for file in execute.artifact_locations %} 30 | - {{ file }} 31 | {% endfor %} 32 | {% endif %} 33 | {% if execute.testrun_results %} 34 | 35 | These are the test results of the scenario: 36 | - {{ execute.name }} 37 | Total Tests: {{ execute.testrun_results.aggregate_testrun_results.total_tests }} 38 | Passed Tests: {{ execute.testrun_results.aggregate_testrun_results.passed_tests }} 39 | Failed Tests: {{ execute.testrun_results.aggregate_testrun_results.failed_tests }} 40 | Skipped Tests: {{ execute.testrun_results.aggregate_testrun_results.skipped_tests }} 41 | 42 | {% endif %} 43 | {% endfor %} 44 | {% endif %} 45 | 46 | {% if scenario.get_reports() %} 47 | {% for report in scenario.get_reports() %} 48 | {% if report.provider == 'polarion' or report.importer_plugin_name == 'polarion' and report.import_results %} 49 | The following is the result of the Polarion import: 50 | {% for results in report.import_results %} 51 | {{ results['testrun-url'] }} 52 | {% endfor %} 53 | {% endif %} 54 | {% if report.provider == 'reportportal' or report.importer_plugin_name == 'reportportal' and report.import_results %} 55 | The following is the result of the Report Portal import: 56 | {{ report.import_results['dashboard_url'] }} 57 | {% endif %} 58 | {% endfor %} 59 | {% endif %} 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /teflo/tasks/execute.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.test 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | from teflo.executors import ExecuteManager 28 | 29 | 30 | class ExecuteTask(TefloTask): 31 | """Execute task.""" 32 | __task_name__ = 'execute' 33 | __concurrent__ = False 34 | 35 | def __init__(self, msg, package, **kwargs): 36 | """Constructor. 37 | 38 | :param msg: task message 39 | :type msg: str 40 | :param kwargs: additional keyword arguments 41 | :type kwargs: dict 42 | """ 43 | super(ExecuteTask, self).__init__(**kwargs) 44 | self.msg = msg 45 | 46 | # create the executor object 47 | self.executor = ExecuteManager(package) 48 | 49 | def run(self): 50 | """Run. 51 | 52 | This method is the main entry point to the task. 53 | """ 54 | self.logger.info(self.msg) 55 | try: 56 | # run the configuration with the given executor 57 | self.executor.run() 58 | except Exception as ex: 59 | self.logger.error('Failed to execute %s' % self.name) 60 | stackmsg = self.get_formatted_traceback() 61 | self.logger.error(ex) 62 | self.logger.error(stackmsg) 63 | raise 64 | -------------------------------------------------------------------------------- /docs/users/definitions/resource_check.rst: -------------------------------------------------------------------------------- 1 | Resource Check 2 | ============== 3 | 4 | Teflo's Resource Dependency Check Section is optional. It is run during the Validate task 5 | Resource_check is a dictionary which takes in three keys **monitored_services (formerly was service), playbook, script** 6 | 7 | Monitored_Services 8 | ~~~~~~~~~~~~~~~~~~ 9 | 10 | User can define a list of external components to check if their status is up or not. 11 | if all components are up the scenario will be executed .If one or more components are 12 | down the scenario will exit with an error. It will also indicate if a component name 13 | given is invalid. 14 | 15 | The key "resource_check_endpoint" must be set in the teflo.cfg file to actually 16 | perform check. If not set this section is ignored. The "resource_check_endpoint" 17 | must be the URL of a "Cachet" status page endpoint. Component names must be valid 18 | for that status page 19 | 20 | .. code-block:: yaml 21 | 22 | [defaults] 23 | log_level=info 24 | workspace=. 25 | data_folder=.teflo 26 | resource_check_endpoint= 27 | 28 | 29 | Playbook/ Script 30 | ~~~~~~~~~~~~~~~~ 31 | 32 | User can put in a list of customized playbooks or scripts to validate certain things 33 | before starting their scenario. if any of the user defined validation playbook/scripts 34 | fail the scenario will not be run. 35 | 36 | All playbooks and scripts are run only on the localhost from where teflo is being executed. 37 | Teflo will not be able to take any output from these scripts/playbooks and make any 38 | decisions based on that 39 | Teflo will consider the resource _check successfull or not based on the return code received 40 | after running the playbook or script 41 | 42 | Teflo uses the ansible to run these playbooks and scripts. User should define playbooks and 43 | scripts similar to how it is defined in the `Execute <./execute.html>`_ section of Teflo 44 | 45 | 46 | Example 1 47 | ~~~~~~~~~ 48 | 49 | Using service, playbook, script 50 | 51 | .. literalinclude:: ../../../examples/docs-usage/resource_check.yml 52 | :lines: 2-43 53 | 54 | Example 2 55 | ~~~~~~~~~ 56 | 57 | Using service 58 | 59 | .. literalinclude:: ../../../examples/docs-usage/resource_check.yml 60 | :lines: 46-61 61 | 62 | 63 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Refactored per https://blog.ionelmc.ro/2015/04/14/tox-tricks-and-patterns/#partial-environment-reuse 2 | [tox] 3 | envlist = py{3}-{unit,scenario},docs,docs-wiki 4 | 5 | [base] 6 | deps = -r{toxinidir}/test-requirements.txt 7 | 8 | [testenv] 9 | usedevelop = true 10 | sitepackages = true 11 | download = true 12 | envdir = 13 | py3,docs,docs-wiki: {toxworkdir}/py3 14 | deps = {[base]deps} 15 | changedir= 16 | unit: tests/functional 17 | scenario: tests/localhost_scenario 18 | setenv = 19 | WORKSPACE=. 20 | HOME=/tmp 21 | PY_VERSION={envname} 22 | TEST_JINJA=yes 23 | whitelist_externals = 24 | teflo 25 | commands = 26 | py{3}-unit: {[unittest]commands} 27 | py{3}-scenario: {[scenariotest]commands} 28 | 29 | [unittest] 30 | commands = 31 | pytest --cov teflo --cov-config=../../tox.ini --cov-report html:../coverage/{envname} --cov-report xml:../coverage/{envname}/coverage.xml \ 32 | --cov-fail-under=50 -v 33 | pycodestyle ../../teflo 34 | 35 | [scenariotest] 36 | commands = 37 | teflo --version 38 | teflo run -s scenario_local.yml -w . -d ./.teflo/{envname} 39 | teflo run -s sdf_library1.yml -w . -d ./.teflo/{envname} 40 | teflo run -s sdf_library2.yml -w . -d ./.teflo/{envname} 41 | teflo run -s sdf_library3.yml -w . -d ./.teflo/{envname} 42 | teflo run -s sdf_library4.yml -w . -d ./.teflo/{envname} 43 | teflo run -s sdf0_test_jinja.yml -w . -d ./.teflo/{envname} 44 | teflo run -s s_test_gv.yml -w . -d ./.teflo/{envname} 45 | 46 | [testenv:docs] 47 | whitelist_externals = 48 | rm 49 | git 50 | commands = 51 | python setup.py build_sphinx 52 | 53 | [testenv:docs-wiki] 54 | whitelist_externals = 55 | {[testenv:docs]whitelist_externals} 56 | find 57 | setenv = 58 | REQUESTS_CA_BUNDLE=/etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt 59 | commands = 60 | sphinx-build -b confluence {posargs} docs/docs_confluence docs/_build/confluence 61 | 62 | [pycodestyle] 63 | exclude = src/teflo/_compat.py 64 | ignore = E112,E126,E127,E241,E242,F401 65 | max-line-length = 120 66 | statistics = True 67 | show-source = True 68 | 69 | [run] 70 | omit =*/teflo/provisioners/ext/beaker_client_plugin.py* 71 | */teflo/provisioners/ext/openstack_libcloud_plugin.py* 72 | 73 | -------------------------------------------------------------------------------- /docs/users/definitions/timeout.rst: -------------------------------------------------------------------------------- 1 | Timeout settings for Teflo Tasks 2 | ================================== 3 | 4 | This feature will allow users to set a time limit for all the teflo tasks. This can be done in either of the following two ways 5 | 6 | 1. defining the **timeout** fields in teflo.cfg. These values will be applied throughout the scenario descriptor file: 7 | 8 | .. code-block:: bash 9 | 10 | [timeout] 11 | provision=500 12 | cleanup=1000 13 | orchestrate=300 14 | execute=200 15 | report=100 16 | validate=10 17 | 18 | 2. defining the **timeout** fields in SDF. Here you can define below timeouts for individual task blocks within the SDF: 19 | 20 | **validate_timeout, provision_timeout, orchestrate_timeout, execute_timeout, report_timeout, cleanup_timeout, notification_timeout** 21 | 22 | .. code-block:: bash 23 | 24 | --- 25 | name: example 26 | description: An example scenario for timeout 27 | 28 | provision: 29 | - name: test 30 | group: client 31 | provisioner: linchpin-wrapper 32 | provider: 33 | name: openstack 34 | credential: openstack 35 | image: rhel-7.4-server-x86_64-released 36 | flavor: m1.small 37 | keypair: {{ key }} 38 | networks: 39 | - provider_net_cci_4 40 | ansible_params: 41 | ansible_user: cloud-user 42 | ansible_ssh_private_key_file: /home/junqizhang/.ssh/OCP 43 | # you define provision_timeout, orchestrate_timeout, cleanup_timeout, report_timeout here from SDF 44 | provision_timeout: 200 45 | 46 | report: 47 | - name: SampleTest.xml 48 | description: import results to polarion 49 | executes: junitTestRun 50 | provider: 51 | credential: polarion-creds 52 | name: polarion 53 | project_id: Teflo1 54 | testsuite_properties: 55 | polarion-lookup-method: name 56 | polarion-testrun-title: e2e-tests 57 | report_timeout: 120 58 | 59 | .. note:: **If the timeout values are defined from SDF, it 60 | will overwrite the timeout values defined from 61 | teflo.cfg** -------------------------------------------------------------------------------- /teflo/executors/ext/ansible_executor_plugin/files/extensions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | Pykwalify extensions module for ansible executor plugin 20 | 21 | Module containing custom validation functions used for ansible executor schema checking. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | 28 | def valid_execute_types(value, rule_obj, path): 29 | """ Verify if only one execute type is set for a execute task""" 30 | match = list() 31 | 32 | types = ['script', 'playbook', 'shell'] 33 | 34 | for item in types: 35 | if item in value.keys() and value[item]: 36 | match.append(item) 37 | 38 | if match.__len__() > 1: 39 | raise AssertionError( 40 | 'Only one execute type can be set for executor ~ %s.\n' 41 | 'Available types: %s\n' 42 | 'Set types: %s' % (value['executor'], types, match) 43 | ) 44 | return True 45 | 46 | 47 | def type_int_list(value, rule_obj, path): 48 | """Verfiy a key's value is either a int or list.""" 49 | if not isinstance(value, (int, list)): 50 | raise AssertionError( 51 | '%s must be either a integer or list of integers.' % path.split('/')[-1] 52 | ) 53 | if isinstance(value, list): 54 | for x in value: 55 | if not isinstance(x, int): 56 | raise AssertionError( 57 | '%s must be either a integer or list of integers.' % path.split('/')[-1] 58 | ) 59 | return True 60 | -------------------------------------------------------------------------------- /teflo/_compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo._compat 20 | 21 | This is a compatibility module that assists on keeping the Teflo 22 | Framework compatible with python 2.x and python 3.x. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | import sys 28 | import ansible 29 | 30 | _ver = sys.version_info 31 | 32 | ansible_ver = int(ansible.__version__.split('.')[:2][1]) 33 | # Python 2.x? 34 | is_py2 = (_ver[0] == 2) 35 | 36 | # Python 3.x? 37 | is_py3 = (_ver[0] == 3) 38 | 39 | # Windows 40 | is_win = sys.platform.startswith('win') 41 | 42 | try: 43 | import simplejson as json 44 | except (ImportError, SyntaxError): 45 | # simplejson does not support Python 3.2, it throws a SyntaxError 46 | # because of u'...' Unicode literals. 47 | import json 48 | 49 | try: 50 | import builtins 51 | except ImportError: 52 | import __builtin__ as builtins 53 | 54 | try: 55 | from ConfigParser import RawConfigParser 56 | except ImportError: 57 | from configparser import RawConfigParser 58 | 59 | try: 60 | string_types = (str, unicode) 61 | except NameError: 62 | string_types = (str, ) 63 | 64 | try: 65 | from urlparse import urlparse 66 | except ImportError: 67 | from urllib.parse import urlparse 68 | 69 | try: 70 | from ConfigParser import ConfigParser 71 | except Exception: 72 | from configparser import ConfigParser 73 | 74 | try: 75 | from ansible.parsing.vault import VaultLib 76 | except ImportError: 77 | from ansible.utils.vault import VaultLib 78 | -------------------------------------------------------------------------------- /teflo/tasks/orchestrate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.install 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | from teflo.orchestrators import ActionOrchestrator 28 | 29 | 30 | class OrchestrateTask(TefloTask): 31 | """Orchestrate task.""" 32 | __task_name__ = 'orchestrate' 33 | __concurrent__ = False 34 | 35 | def __init__(self, msg, package, **kwargs): 36 | """Constructor. 37 | 38 | :param msg: task message 39 | :type msg: str 40 | :param package: package reference 41 | :type package: object 42 | :param kwargs: additional keyword arguments 43 | :type kwargs: dict 44 | """ 45 | super(OrchestrateTask, self).__init__(**kwargs) 46 | self.msg = msg 47 | 48 | # create the orchestrator object 49 | self.orchestrator = ActionOrchestrator(package) 50 | 51 | def run(self): 52 | """Run. 53 | 54 | This method is the main entry point to the task. 55 | """ 56 | self.logger.info(self.msg) 57 | try: 58 | # run the configuration with the given orchestrator 59 | self.orchestrator.run() 60 | except Exception as ex: 61 | self.logger.error('Failed to run orchestration %s ' % self.name) 62 | stackmsg = self.get_formatted_traceback() 63 | self.logger.error(ex) 64 | self.logger.error(stackmsg) 65 | raise 66 | -------------------------------------------------------------------------------- /docs/users/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | This page is intended to provide you with detailed examples on how you can use 5 | teflo to perform various actions. Some of the actions below may redirect you 6 | to a git repository where further detail is given. 7 | 8 | ---- 9 | 10 | Test Setup & Execution 11 | ---------------------- 12 | 13 | This section provides you with detailed examples on how teflo can perform 14 | test setup and execution using common test frameworks. Below you will find 15 | sub-sections with examples for installation and execution using commonly used 16 | test frameworks. Each framework has an associated repository containing all 17 | necessary files to call teflo to demonstrate test setup and execution. Each 18 | of the examples demonstrates how teflo consumes the external 19 | automated scripts (i.e, ansible roles/playbooks, bash scripts, etc) to install 20 | the test frameworks, and how teflo executes example tests and gets the 21 | artifacts of the execution. 22 | 23 | .. note:: 24 | 25 | These frameworks below are just examples on how you can use teflo to run 26 | existing automation you may have to install/setup/execute using common 27 | test frameworks. Since teflos primary purpose is to conduct "orchestrate" 28 | the E2E flow of a multi-product scenario, it has the flexibility to consume 29 | any sort of automation to run against your scenarios test machines defined. 30 | This allows you to focus on building the automation to setup test 31 | frameworks and then just tell teflo how you wish to run it. 32 | 33 | Junit 34 | ~~~~~ 35 | 36 | Please reference the example `junit example`_ for all details on how you 37 | can execute this example with teflo to run a junit example. 38 | 39 | Pytest 40 | ~~~~~~ 41 | 42 | Please reference the example `pytest example`_ for all details on how you 43 | can execute this example with teflo to run a pytest example. 44 | 45 | Restraint 46 | ~~~~~~~~~ 47 | 48 | Please reference the example `restraint example`_ for all details on how you 49 | can execute this example with teflo to run a restraint example. 50 | 51 | ---- 52 | 53 | .. _junit example: https://github.com/RedHatQE/teflo_examples/tree/master/junit-example 54 | .. _pytest example: https://github.com/RedHatQE/teflo_examples/tree/master/pytest-example 55 | .. _restraint example: https://github.com/RedHatQE/teflo_examples/tree/master/restraint-example 56 | -------------------------------------------------------------------------------- /teflo/orchestrators/ext/ansible_orchestrator_plugin/files/extensions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | Pykwalify extensions module for ansible orchestrator plugin 20 | 21 | Module containing custom validation functions used for ansible orchestrator schema checking. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | 28 | def valid_action_types(value, rule_obj, path): 29 | """ Verify if only one action type is set for a orchestrate task""" 30 | match = list() 31 | 32 | types = ['ansible_script', 'ansible_playbook', 'ansible_shell'] 33 | 34 | for item in types: 35 | if item in value.keys() and value[item]: 36 | match.append(item) 37 | 38 | if match.__len__() > 1: 39 | raise AssertionError( 40 | 'Only one action type can be set for orchestrator\n' 41 | 'Available action types: %s\n' 42 | 'Set types: %s' % (types, match) 43 | ) 44 | elif match.__len__() == 0: 45 | raise AssertionError( 46 | 'At lease one action type should be set for orchestrator \n' 47 | 'Available action types: %s\n' % types 48 | ) 49 | return True 50 | 51 | 52 | def valid_ansible_script_type(value, rule_obj, path): 53 | 54 | """ Verify if ansible_script has appropriate keys from the given list 55 | """ 56 | extra_args = ['name', 'creates', 'decrypt', 'executable', 'removes', 'warn', 'stdin', 'stdin_add_newline'] 57 | if False in [key in extra_args and isinstance(val, str) for key, val in value.items()]: 58 | raise AssertionError('ansible_script dictionary is using a key not present in this list %s' % extra_args) 59 | else: 60 | return True 61 | -------------------------------------------------------------------------------- /examples/docs-usage/notification.yml: -------------------------------------------------------------------------------- 1 | --- 2 | notifications: 3 | - name: test_email 4 | notifier: email-notifier 5 | credential: email 6 | on_success: true 7 | to: 8 | - jsmith@redhat.com 9 | from: qe-rh@redhat.com 10 | subject: This is teflo notification 11 | 12 | --- 13 | notifications: 14 | - name: msg_template 15 | notifier: email-notifier 16 | credential: email 17 | on_start: true 18 | to: 19 | - jsmith@redhat.com 20 | - fbar@redhat.com 21 | from: qe-team@redhat.com 22 | subject: test email notification using default template {{ UUID }} 23 | message_template: email_templ.txt 24 | 25 | --- 26 | notifications: 27 | - name: msg_body_test 28 | notifier: email-notifier 29 | credential: email 30 | on_failure: true 31 | on_tasks: 32 | - validate 33 | - provision 34 | to: [jsnith@redhat.com, fbar@redhat.com] 35 | from: qe-team@redhat.com 36 | subject: test notification using message body. 37 | message_body: | 38 | Hello All, 39 | 40 | This is a Teflo Test notification. For Jenkins Job {{ Job }}. 41 | 42 | Thanks, 43 | 44 | Waldo 45 | 46 | --- 47 | notifications: 48 | - name: msg_test 49 | notifier: email-notifier 50 | credential: email 51 | on_failure: true 52 | to: [jsnith@redhat.com, fbar@redhat.com] 53 | from: qe-team@redhat.com 54 | subject: test notification using message attachments. 55 | attachments: 56 | - workpsace/folder/file.txt 57 | 58 | --- 59 | notifications: 60 | - name: msg_test 61 | notifier: email-notifier 62 | credential: email 63 | on_demand: true 64 | to: [jsnith@redhat.com, fbar@redhat.com] 65 | from: qe-team@redhat.com 66 | subject: test notification only when manually triggered. 67 | 68 | --- 69 | notifications: 70 | - name: msg_template 71 | notifier: email-notifier 72 | credential: email 73 | on_start: true 74 | to: 75 | - jsmith@redhat.com 76 | - fbar@redhat.com 77 | from: qe-team@redhat.com 78 | subject: test email notification using default template {{ UUID }} 79 | message_template: email_templ.txt 80 | 81 | --- 82 | notifications: 83 | - name: msg_template 84 | notifier: email-notifier 85 | credential: email 86 | on_tasks: ['provision'] 87 | to: 88 | - jsmith@redhat.com 89 | - fbar@redhat.com 90 | from: qe-team@redhat.com 91 | subject: test email notification is for user {{ username }} 92 | message_template: {{ msg_template }} 93 | -------------------------------------------------------------------------------- /teflo/orchestrators/action_orchestrator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | This is a generic interface that processes teflo's orchestration actions. 21 | 22 | :copyright: (c) 2022 Red Hat, Inc. 23 | :license: GPLv3, see LICENSE for more details. 24 | """ 25 | 26 | from ..core import LoggerMixin, TimeMixin 27 | from ..exceptions import TefloOrchestratorError 28 | 29 | 30 | class ActionOrchestrator(LoggerMixin, TimeMixin): 31 | """Action Orchestrator. 32 | 33 | This is a generic interface that processes teflo's orchestration actions. 34 | """ 35 | __orchestrator_name__ = 'action-orchestrator' 36 | 37 | def __init__(self, package): 38 | """Constructor. 39 | 40 | Action resource 41 | 42 | :param action: teflo action resource 43 | :type action: object 44 | """ 45 | self.action = package 46 | self.plugin = getattr(package, 'orchestrator')(package) 47 | 48 | def validate(self): 49 | """Validate the orchestration action params supplied are supported by the plugin.""" 50 | 51 | try: 52 | self.plugin.validate() 53 | except Exception: 54 | raise 55 | else: 56 | self.logger.info('successfully validated scenario Action %s against the schema!' % self.plugin.action_name) 57 | 58 | def run(self): 59 | """Run method for orchestrator. 60 | """ 61 | res = self.plugin.run() 62 | if res == 0: 63 | setattr(self.action, 'status', 0) 64 | self.logger.info('Orchestration passed : Successfully completed orchestrate action: %s.' 65 | % self.plugin.action_name) 66 | else: 67 | setattr(self.action, 'status', 1) 68 | raise TefloOrchestratorError("Orchestration failed : Failed to perform %s" % self.plugin.action_name) 69 | -------------------------------------------------------------------------------- /teflo/executors/ext/ansible_executor_plugin/files/schema.yml: -------------------------------------------------------------------------------- 1 | # default schema for ansible executor 2 | 3 | type: map 4 | allowempty: True 5 | func: valid_execute_types 6 | mapping: 7 | git: 8 | allowempty: True 9 | type: seq 10 | sequence: 11 | - type: map 12 | mapping: 13 | repo: 14 | required: True 15 | type: str 16 | version: 17 | required: True 18 | type: str 19 | dest: 20 | required: True 21 | type: str 22 | shell: 23 | allowempty: True 24 | type: seq 25 | sequence: 26 | - type: map 27 | mapping: 28 | chdir: 29 | type: str 30 | creates: 31 | type: str 32 | decrypt: 33 | type: str 34 | executable: 35 | type: str 36 | removes: 37 | type: str 38 | warn: 39 | type: str 40 | stdin: 41 | type: str 42 | stdin_add_newline: 43 | type: str 44 | ignore_rc: 45 | type: bool 46 | valid_rc: 47 | type: any 48 | func: type_int_list 49 | command: 50 | required: True 51 | type: str 52 | script: 53 | allowempty: True 54 | type: seq 55 | sequence: 56 | - type: map 57 | mapping: 58 | chdir: 59 | type: str 60 | creates: 61 | type: str 62 | decrypt: 63 | type: str 64 | executable: 65 | type: str 66 | removes: 67 | type: str 68 | warn: 69 | type: str 70 | stdin: 71 | type: str 72 | stdin_add_newline: 73 | type: str 74 | ignore_rc: 75 | type: bool 76 | valid_rc: 77 | type: any 78 | func: type_int_list 79 | name: 80 | required: True 81 | type: str 82 | playbook: 83 | allowempty: True 84 | type: seq 85 | sequence: 86 | - type: map 87 | mapping: 88 | chdir: 89 | type: str 90 | ignore_rc: 91 | type: bool 92 | name: 93 | required: True 94 | type: str 95 | artifacts: 96 | type: seq 97 | sequence: 98 | - type: str 99 | artifact_locations: 100 | type: seq 101 | sequence: 102 | - type: str 103 | ignore_rc: 104 | type: bool 105 | environment_vars: 106 | allowempty: True 107 | type: map 108 | 109 | -------------------------------------------------------------------------------- /teflo/tasks/provision.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.provision 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | from ..provisioners import AssetProvisioner 28 | 29 | 30 | class ProvisionTask(TefloTask): 31 | """Provision task.""" 32 | __task_name__ = 'provision' 33 | __concurrent__ = True 34 | 35 | def __init__(self, msg, asset, **kwargs): 36 | """Constructor. 37 | 38 | :param msg: task message 39 | :type msg: str 40 | :param asset: asset reference 41 | :type asset: str 42 | :param kwargs: additional keyword arguments 43 | :type kwargs: dict 44 | """ 45 | super(ProvisionTask, self).__init__(**kwargs) 46 | self.msg = msg 47 | self.provision = True 48 | if not asset.is_static: 49 | # create the provisioner object to create assets 50 | self.provisioner = AssetProvisioner(asset) 51 | else: 52 | self.provision = False 53 | self.logger.warning('Asset %s is static, provision will be ' 54 | 'skipped.' % getattr(asset, 'name')) 55 | 56 | def run(self): 57 | """Run. 58 | 59 | This method is the main entry point to the task. 60 | """ 61 | # provision the asset given in their declared provider 62 | if self.provision: 63 | self.logger.info(self.msg) 64 | try: 65 | return self.provisioner.create() 66 | except Exception as ex: 67 | self.logger.error('Failed to provision asset %s' % self.name) 68 | stackmsg = self.get_formatted_traceback() 69 | self.logger.error(ex) 70 | self.logger.error(stackmsg) 71 | raise 72 | -------------------------------------------------------------------------------- /teflo/notifiers/notification_emitter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | teflo.provisioners.host_provisioner 21 | 22 | Base provisioner module to be used as an interface for implementing any 23 | new provisioners within teflo. 24 | 25 | :copyright: (c) 2022 Red Hat, Inc. 26 | :license: GPLv3, see LICENSE for more details. 27 | """ 28 | 29 | from pprint import pformat 30 | 31 | from teflo.core import LoggerMixin, TimeMixin 32 | from teflo.helpers import mask_credentials_password 33 | import copy 34 | import json 35 | 36 | 37 | class Notifier(LoggerMixin, TimeMixin): 38 | """Notification Emitter class. 39 | 40 | This class is the generic interface that sends out notifications 41 | 42 | """ 43 | __notification_name__ = 'notifier' 44 | 45 | def __init__(self, notification): 46 | """Constructor. 47 | 48 | Notification resource 49 | 50 | :param notification: teflo notification resource 51 | :type notification: object 52 | """ 53 | 54 | self.plugin = getattr(notification, 'notifier')(notification) 55 | 56 | def validate(self): 57 | """ 58 | 59 | validate the params provided are supported by the plugin 60 | :return: 61 | """ 62 | try: 63 | self.plugin.validate() 64 | except Exception: 65 | raise 66 | else: 67 | self.logger.info('successfully validated scenario Notification against the schema!') 68 | 69 | def notify(self): 70 | """Notify method. Calls the plugin notify method 71 | """ 72 | name = getattr(getattr(self.plugin, 'notification'), 'name') 73 | try: 74 | self.logger.info('Triggering notification %s.' % name) 75 | self.plugin.notify() 76 | self.logger.info('Successfully triggered notification %s.' % name) 77 | 78 | except Exception as ex: 79 | self.logger.error(ex) 80 | raise 81 | -------------------------------------------------------------------------------- /tests/functional/conftest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.conftest 21 | 22 | Module containing hooks used by all tests. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | from fixtures import action_resource, action_resource_cleanup, scenario, \ 29 | report_resource, execute_resource, host, default_host_params, \ 30 | scenario_resource, config, master_child_scenario, scenario1, asset1, asset3, action1,\ 31 | scenario_resource1, execute1, execute2, execute3, asset2, action2, scenario_labels, notification_default_resource, \ 32 | notification_on_start_resource, notification_on_demand_resource, notification_on_success_resource, \ 33 | notification_on_failure_resource, default_note_params,\ 34 | scenario_resource1, execute1, execute2, asset2, action2, scenario_labels,\ 35 | timeout_param_provision, timeout_param_execute,\ 36 | timeout_param_report, timeout_param_orchestrate, \ 37 | basic_scenario_graph_with_provision_only, scenario_graph, scenario_graph1 38 | 39 | __all__ = [ 40 | basic_scenario_graph_with_provision_only, 41 | action_resource, 42 | action_resource_cleanup, 43 | config, 44 | default_host_params, 45 | execute_resource, 46 | execute1, 47 | execute2, 48 | execute3, 49 | host, 50 | asset1, 51 | asset2, 52 | asset3, 53 | action1, 54 | action2, 55 | report_resource, 56 | scenario, 57 | scenario1, 58 | scenario_resource, 59 | scenario_resource1, 60 | scenario_labels, 61 | scenario_graph, 62 | master_child_scenario, 63 | notification_default_resource, 64 | notification_on_start_resource, 65 | notification_on_demand_resource, 66 | notification_on_success_resource, 67 | notification_on_failure_resource, 68 | default_note_params, 69 | timeout_param_provision, 70 | timeout_param_execute, 71 | timeout_param_report, 72 | timeout_param_orchestrate, 73 | scenario_graph1 74 | ] 75 | -------------------------------------------------------------------------------- /tests/functional/test_action_orchestrator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_action_orchestrator 21 | 22 | Unit tests for testing teflo task orchestrator class. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | import pytest 29 | import mock 30 | from teflo.orchestrators.action_orchestrator import ActionOrchestrator 31 | from teflo.core import OrchestratorPlugin 32 | from teflo.exceptions import TefloOrchestratorError 33 | 34 | 35 | @pytest.fixture(scope='class') 36 | def plugin(): 37 | pg = mock.MagicMock(spec=OrchestratorPlugin, __plugin_name__='ansible') 38 | pg.action_name = 'action1' 39 | pg.run = mock.MagicMock(return_value=0) 40 | pg.validate = mock.MagicMock(return_value=[]) 41 | return pg 42 | 43 | 44 | @pytest.fixture 45 | def action_orchestrator(action_resource): 46 | action_orchestrator = ActionOrchestrator(action_resource) 47 | return action_orchestrator 48 | 49 | 50 | class TestActionOrchestrator(object): 51 | 52 | @staticmethod 53 | def test_task_orchestrator_constructor(action_orchestrator): 54 | assert isinstance(action_orchestrator, ActionOrchestrator) 55 | 56 | @staticmethod 57 | def test_task_orchestrator_validate(plugin, action_orchestrator): 58 | action_orchestrator.plugin = plugin 59 | action_orchestrator.validate() 60 | plugin.validate.assert_called() 61 | 62 | @staticmethod 63 | def test_task_orchestrator_run(plugin, action_orchestrator): 64 | action_orchestrator.plugin = plugin 65 | action_orchestrator.run() 66 | plugin.run.assert_called() 67 | 68 | @staticmethod 69 | def test_task_orchestrator_run_failure(plugin, action_orchestrator): 70 | plugin.run.return_value = 1 71 | action_orchestrator.plugin = plugin 72 | with pytest.raises(TefloOrchestratorError) as ex: 73 | action_orchestrator.run() 74 | assert "Orchestration failed : Failed to perform action1" in ex.value.args[0] 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /teflo/tasks/report.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.report 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | from .._compat import string_types 28 | from ..importers import ArtifactImporter 29 | 30 | 31 | class ReportTask(TefloTask): 32 | """Report task.""" 33 | __task_name__ = 'report' 34 | 35 | def __init__(self, msg, package, **kwargs): 36 | """Constructor. 37 | 38 | :param msg: task message 39 | :type msg: str 40 | :param kwargs: additional keyword arguments 41 | :type kwargs: dict 42 | """ 43 | super(ReportTask, self).__init__(**kwargs) 44 | self.msg = msg 45 | self.do_import = True 46 | 47 | # create the artifact importer interface and supply the plugins to this interface 48 | self.importer = ArtifactImporter(package) 49 | 50 | if not package.do_import: 51 | self.do_import = False 52 | 53 | def run(self): 54 | """Run. 55 | 56 | This method is the main entry point to the task. 57 | """ 58 | self.logger.debug(self.msg) 59 | 60 | try: 61 | # check if the artifacts are on disk. 62 | self.importer.validate_artifacts() 63 | except Exception as ex: 64 | self.logger.error('Failed to run report %s ' % self.name) 65 | stackmsg = self.get_formatted_traceback() 66 | self.logger.error(ex) 67 | self.logger.error(stackmsg) 68 | raise 69 | 70 | if self.do_import: 71 | try: 72 | # run the configuration with the given importer 73 | self.importer.import_artifacts() 74 | except Exception as ex: 75 | self.logger.error('Failed to run report %s ' % self.name) 76 | stackmsg = self.get_formatted_traceback() 77 | self.logger.error(ex) 78 | self.logger.error(stackmsg) 79 | raise 80 | -------------------------------------------------------------------------------- /tests/functional/test_execute_manager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_execute_manager 21 | 22 | Unit tests for testing teflo task orchestrator class. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | import pytest 29 | import mock 30 | from teflo.orchestrators.action_orchestrator import ActionOrchestrator 31 | 32 | from teflo.executors.execute_manager import ExecuteManager 33 | from teflo.core import ExecutorPlugin 34 | from teflo.exceptions import TefloExecuteError 35 | 36 | from teflo.core import OrchestratorPlugin 37 | from teflo.exceptions import TefloOrchestratorError 38 | 39 | 40 | @pytest.fixture(scope='class') 41 | def plugin(): 42 | pg = mock.MagicMock(spec=ExecutorPlugin, __plugin_name__='runner') 43 | pg.execute_name = 'execute1' 44 | pg.run = mock.MagicMock(return_value=0) 45 | pg.validate = mock.MagicMock(return_value=[]) 46 | return pg 47 | 48 | 49 | @pytest.fixture 50 | def execute_manager(execute_resource): 51 | execute_manager = ExecuteManager(execute_resource) 52 | return execute_manager 53 | 54 | 55 | class TestExecuteManager(object): 56 | 57 | @staticmethod 58 | def test_task_executor_constructor(execute_manager): 59 | assert isinstance(execute_manager, ExecuteManager) 60 | 61 | @staticmethod 62 | def test_task_executor_validate(plugin, execute_manager): 63 | execute_manager.plugin = plugin 64 | execute_manager.validate() 65 | plugin.validate.assert_called() 66 | 67 | @staticmethod 68 | def test_task_executor_run(plugin, execute_manager): 69 | execute_manager.plugin = plugin 70 | execute_manager.run() 71 | plugin.run.assert_called() 72 | 73 | @staticmethod 74 | def test_task_executor_run_failure(plugin, execute_manager): 75 | plugin.run.return_value = 1 76 | execute_manager.plugin = plugin 77 | with pytest.raises(TefloExecuteError) as ex: 78 | execute_manager.run() 79 | assert "Execute stage failed : Failed to perform execute1" in ex.value.args[0] 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Teflo! 2 | ================== 3 | 4 | .. warning:: 5 | **This project is in maintenance mode and will not have any new feature development.** 6 | 7 | What is Teflo? 8 | --------------- 9 | 10 | **TEFLO** stands for (**T** est **E** xecution **F** ramework **L** ibraries and **O** bjects) 11 | 12 | Teflo is an orchestration software that controls the flow of a set of testing scenarios. 13 | It is a standalone tool that includes all aspects of the workflow. 14 | It allows users to provision machines, deploy software, execute tests against them and 15 | manage generated artifacts and report results. 16 | 17 | Teflo Provides *structure*, *readability*, *extensibility* and *flexibility* by : 18 | 19 | - providing a DSL (YAML) to express a test workflow as a series of steps. 20 | - enabling integration of external tooling to execute the test workflow as defined by the steps. 21 | 22 | Teflo can be used for an E2E (end to end) multi-product scenario. Teflo handles coordinating the 23 | E2E task workflow to drive the scenario execution. 24 | 25 | 26 | What does an E2E workflow consist of? 27 | ------------------------------------- 28 | 29 | At a high level teflo executes the following tasks when processing a scenario. 30 | 31 | - Provision system resources 32 | - Perform system configuration 33 | - Install products 34 | - Configure products 35 | - Install test frameworks 36 | - Configure test frameworks 37 | - Execute tests 38 | - Report results 39 | - Destroy system resources 40 | - Send Notifications 41 | 42 | Teflo is a test execution framework. It is a standalone tool written in Python. 43 | Teflo can perform the following tasks 44 | 45 | **Provision** - Create resources they want to test on (physical resources, VMs etc) 46 | 47 | **Orchestrate** - Configure these resources , like install packages on them, run scripts, ansible playbooks etc 48 | 49 | **Execute** - Execute actual tests on the configured resources 50 | 51 | **Report** - Send or collect logs from the run tests 52 | 53 | **Notification** - Send email/gchat/slack notification during each stage of teflo run or at the end based on the triggers set 54 | 55 | **Cleanup** - Cleanup all the deployed resources. 56 | 57 | These tasks can be run individually or together. 58 | 59 | Teflo follows a pluggable architechture, where users can add different pluggins to support external tools 60 | Below is a diagram that gives you a quick overview of Teflo workflow 61 | 62 | .. image:: _static/teflo_workflow.png 63 | 64 | * To learn more about how to set up and use Teflo please check out the `Users Guide `__ 65 | * To know how to create a custom plugin checkout `Developers Guide `__ 66 | * To know about our release cadence and contribution policy check out `Release Cadence `__ 67 | 68 | .. include:: contents.rst.inc 69 | 70 | 71 | -------------------------------------------------------------------------------- /teflo/files/extensions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | Pykwalify extensions module. 20 | 21 | Module containing custom validation functions used for schema checking. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | from teflo.constants import PROVISIONERS 28 | from teflo.helpers import get_executor_plugin_class, get_executors_plugin_list, get_orchestrators_plugin_list 29 | 30 | 31 | def type_str_list(value, rule_obj, path): 32 | """Verify a key's value is either a string or list.""" 33 | if not isinstance(value, (str, list)): 34 | raise AssertionError( 35 | '%s must be either a string or list.' % path.split('/')[-1] 36 | ) 37 | return True 38 | 39 | 40 | def valid_orchestrator(value, rule_obj, path): 41 | """Verify the given orchestrator is a valid selection by teflo.""" 42 | 43 | orchestrators = get_orchestrators_plugin_list() 44 | if value.lower() not in orchestrators: 45 | raise AssertionError( 46 | 'Orchestrator %s is invalid.\n' 47 | 'Available orchestrators %s' % (value, orchestrators) 48 | ) 49 | return True 50 | 51 | 52 | def valid_executor(value, rule_obj, path): 53 | """Verify the given executor is a valid selection by teflo.""" 54 | executors = get_executors_plugin_list() 55 | if value.lower() not in executors: 56 | raise AssertionError( 57 | 'Executor %s is invalid.\n' 58 | 'Available executors %s' % (value, executors) 59 | ) 60 | return True 61 | 62 | 63 | def check_provider_present(value, rule_obj, path): 64 | if value.get('provider'): 65 | raise AssertionError( 66 | 'Provider key is no longer supported %s. ' 67 | 'Visit https://teflo.readthedocs.io/en/latest/users/definitions/provision.html#provision to see examples ' 68 | 'for provisioning assets' % value.get('provider') 69 | ) 70 | if not value.get('provisioner') and not value.get("ip_address"): 71 | raise AssertionError( 72 | 'If provisioner is not provided, an ip_address is needed for considering the asset as static' 73 | ) 74 | return True 75 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Welcome to Teflo! 2 | ================== 3 | .. warning:: 4 | **This project is in maintenance mode and will not have any new feature development.** 5 | 6 | What is Teflo? 7 | --------------- 8 | 9 | **TEFLO** stands for (**T** est **E** xecution **F** ramework **L** ibraries and **O** bjects) 10 | 11 | Teflo is an orchestration software that controls the flow of a set of testing scenarios. 12 | It is a standalone tool written in Python that includes all aspects of the workflow. 13 | It allows users to provision machines, deploy software, execute tests against them and 14 | manage generated artifacts and report results. 15 | 16 | Teflo Provides *structure*, *readability*, *extensibility* and *flexibility* by : 17 | 18 | - providing a YAML file to express a test workflow as a series of steps. 19 | - enabling integration of external tooling to execute the test workflow as defined by the steps. 20 | 21 | Teflo can be used for an E2E (end to end) multi-product scenario. Teflo handles coordinating the 22 | E2E task workflow to drive the scenario execution. 23 | 24 | Teflo can be used for an E2E (end to end) multi-product scenario. Teflo handles coordinating the 25 | E2E task workflow to drive the scenario execution. 26 | 27 | What does an E2E workflow consist of? 28 | ------------------------------------- 29 | 30 | At a high level teflo executes the following tasks when processing a scenario. 31 | 32 | - Provision system resources 33 | - Perform system configuration 34 | - Install products 35 | - Configure products 36 | - Install test frameworks 37 | - Configure test frameworks 38 | - Execute tests 39 | - Report results 40 | - Destroy system resources 41 | - Send Notifications 42 | 43 | Teflo has following stages 44 | 45 | **Provision** - Create resources to test against (physical resources, VMs etc) 46 | 47 | **Orchestrate** - Configure the provisioned resources (e.g. install packages on them, run scripts, ansible playbooks etc) 48 | 49 | **Execute** - Execute tests on the configured resources 50 | 51 | **Report** - Send or collect logs from the tests run 52 | 53 | **Notification** - Send email/gchat/slack notification during each stage of teflo run or at the end based on the set triggers 54 | 55 | **Cleanup** - Cleanup all the deployed resources. 56 | 57 | These stages can be run individually or together. 58 | 59 | 60 | Teflo follows a plugable architechture, where users can add different pluggins to support external tools 61 | Below is a diagram that gives you a quick overview of the Teflo workflow 62 | 63 | .. image:: /docs/_static/teflo_workflow.png 64 | 65 | * To learn more about how to set up and use Teflo please check out https://teflo.readthedocs.io/en/latest/ 66 | * To know how to create a custom plugin check out https://teflo.readthedocs.io/en/latest/developers/development.html#how-to-write-an-plugin-for-teflo 67 | * To know about our release cadence and contribution policy check out https://teflo.readthedocs.io/en/latest/developers/development.html#release-cadence -------------------------------------------------------------------------------- /teflo/provisioners/ext/bkr_client_plugin/schema.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # default beaker client provisioner schema 3 | 4 | type: map 5 | allowempty: True 6 | mapping: 7 | arch: 8 | type: str 9 | required: True 10 | variant: 11 | type: str 12 | required: True 13 | distro: 14 | type: str 15 | required: False 16 | family: 17 | type: str 18 | required: False 19 | whiteboard: 20 | type: str 21 | required: False 22 | kernel_options: 23 | required: False 24 | type: seq 25 | sequence: 26 | - type: str 27 | kernel_post_options: 28 | required: False 29 | type: seq 30 | sequence: 31 | - type: str 32 | host_requires_options: 33 | required: False 34 | type: seq 35 | sequence: 36 | - type: str 37 | distro_requires_options: 38 | required: False 39 | type: seq 40 | sequence: 41 | - type: str 42 | virtual_machine: 43 | required: False 44 | type: bool 45 | virt_capable: 46 | required: False 47 | type: bool 48 | retention_tag: 49 | required: False 50 | type: str 51 | tag: 52 | required: False 53 | type: str 54 | priority: 55 | required: False 56 | type: str 57 | jobgroup: 58 | required: False 59 | type: str 60 | key_values: 61 | required: False 62 | type: str 63 | timeout: 64 | required: False 65 | type: int 66 | hostname: 67 | required: False 68 | type: str 69 | ip_address: 70 | required: False 71 | type: str 72 | job_id: 73 | required: False 74 | type: str 75 | ssh_key: 76 | required: False 77 | type: str 78 | func: valid_file_exist 79 | username: 80 | required: False 81 | type: str 82 | password: 83 | required: False 84 | type: str 85 | taskparam: 86 | required: False 87 | type: seq 88 | sequence: 89 | - type: str 90 | ignore_panic: 91 | required: False 92 | type: str 93 | kickstart: 94 | required: False 95 | type: str 96 | func: valid_file_exist 97 | ksmeta: 98 | required: False 99 | type: seq 100 | sequence: 101 | - type: str 102 | ksappends: 103 | required: False 104 | type: seq 105 | sequence: 106 | - type: str 107 | job_url: 108 | required: False 109 | type: str 110 | credential: 111 | required: False 112 | type: map 113 | mapping: 114 | hub_url: 115 | required: True 116 | type: str 117 | keytab_principal: 118 | required: False 119 | type: str 120 | keytab: 121 | required: False 122 | type: str 123 | username: 124 | required: False 125 | type: str 126 | password: 127 | required: False 128 | type: str 129 | ca_cert: 130 | required: False 131 | type: str 132 | realm: 133 | required: False 134 | type: str 135 | service: 136 | required: False 137 | type: str 138 | ccache: 139 | required: False 140 | type: str 141 | -------------------------------------------------------------------------------- /teflo/executors/execute_manager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | 21 | This is a generic interface that processes teflo's execute tasks. 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | 27 | from ..core import LoggerMixin, TimeMixin 28 | from ..exceptions import TefloExecuteError 29 | 30 | 31 | class ExecuteManager(LoggerMixin, TimeMixin): 32 | """ The main executor for Teflo. 33 | 34 | The runner class provides three different types on how you can execute 35 | tests. Its intention is to be generic enough where you just need to supply 36 | your test commands and it will process them. All tests executed against 37 | remote hosts will be run through ansible. 38 | """ 39 | 40 | __executor_name__ = 'execute_manager' 41 | 42 | def __init__(self, package): 43 | """Constructor. 44 | 45 | :param package: execute resource 46 | :type package: object 47 | """ 48 | self.execute = package 49 | self.plugin = getattr(package, 'executor')(package) 50 | 51 | # # attribute defining overall status of test execution. why is this 52 | # # needed? when a test fails we handle the exception raised and call 53 | # # the method to archive test artifacts. once fetching artifacts is 54 | # # finished this status is used to fail teflo (if needed) 55 | # self.status = 0 56 | 57 | def validate(self): 58 | """Validate the executes params supplied are supported by the plugin.""" 59 | 60 | try: 61 | self.plugin.validate() 62 | except Exception: 63 | raise 64 | else: 65 | self.logger.info('successfully validated scenario Execute resource %s against the schema!' 66 | % self.plugin.execute_name) 67 | 68 | def run(self): 69 | 70 | """Run method for executor. 71 | """ 72 | res = self.plugin.run() 73 | if res == 0: 74 | setattr(self.execute, 'status', 0) 75 | self.logger.info('Execute stage passed : Successfully completed execute task: %s.' 76 | % self.plugin.execute_name) 77 | else: 78 | setattr(self.execute, 'status', 1) 79 | raise TefloExecuteError("Execute stage failed : Failed to perform %s" % self.plugin.execute_name) 80 | -------------------------------------------------------------------------------- /docs/users/scenario_descriptor.rst: -------------------------------------------------------------------------------- 1 | Scenario Descriptor 2 | =================== 3 | 4 | This page is intended to explain the input to teflo. The goal and focus behind 5 | teflos input is to be simple and transparent. It uses common language to 6 | describe the entire scenario (E2E). The input is written in YAML. The term 7 | used to reference teflo's input is a scenario descriptor file. You will hear 8 | this throughout teflo's documentation. 9 | 10 | Every scenario descriptor file is broken down into different sections. Below is 11 | a table of the keys that correlate to the different sections. 12 | 13 | .. list-table:: 14 | :widths: auto 15 | :header-rows: 1 16 | 17 | * - Key 18 | - Description 19 | - Type 20 | - Required 21 | 22 | * - name 23 | - The name of the scenario descriptor file. 24 | - String 25 | - True 26 | 27 | * - description 28 | - A description of the intent of the scenario. 29 | - String 30 | - False 31 | 32 | * - resource_check 33 | - A list of external resources the scenario depends on 34 | that Teflo can check in Semaphore before running 35 | the scenario. 36 | - List 37 | - False 38 | 39 | * - include 40 | - A list of scenario descriptor files that should be included 41 | when running the scenario. 42 | - List 43 | - False 44 | 45 | * - provision 46 | - A list that contains blocks of Asset definitions that should be dynamically 47 | provisioned or statically defined to be used by the rest of the scenario. 48 | - List 49 | - False 50 | 51 | * - orchestrate 52 | - A list that contains blocks of Action definitions that define scripts or 53 | playbooks that should be run to configure the assets defined in the provision. 54 | - List 55 | - False 56 | 57 | * - execute 58 | - A list that contains blocks of Execute definitions that define scripts, 59 | commands, or playbooks that execute tests on the appropriately configured assets. 60 | - List 61 | - False 62 | 63 | * - report 64 | - A list that contains blocks of Report definitions that should be run 65 | to import test artifacts collected during test execution to a desired 66 | reporting system. 67 | - List 68 | - False 69 | 70 | 71 | Each section relates to a particular component within teflo. You can learn about this at 72 | the `architecture <../developers/architecture.html>`_ page. Below are sub pages which go 73 | into further detail explaining the different sections. 74 | 75 | .. toctree:: 76 | :maxdepth: 1 77 | 78 | definitions/resource_check 79 | definitions/credentials 80 | definitions/include 81 | definitions/provision 82 | definitions/orchestrate 83 | definitions/execute 84 | definitions/report 85 | definitions/notifications 86 | definitions/timeout 87 | 88 | When we put all of these sections together, we have a complete scenario to 89 | provide to teflo. You can see an example of a complete scenario descriptor 90 | below: 91 | 92 | .. literalinclude:: ../../examples/docs-usage/template.yml 93 | -------------------------------------------------------------------------------- /examples/docs-usage/include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Include_example1 3 | description: Descriptor file with include section 4 | 5 | resource_check: 6 | 7 | include: 8 | - provision.yml 9 | 10 | orchestrate: 11 | . 12 | . 13 | . 14 | execute: 15 | . 16 | . 17 | . 18 | report: 19 | . 20 | . 21 | . 22 | --- 23 | name: Include_example2 24 | description: Descriptor file with include section 25 | 26 | include: 27 | - provision.yml 28 | - orchestrate.yml 29 | 30 | execute: 31 | . 32 | . 33 | . 34 | 35 | report: 36 | . 37 | . 38 | . 39 | 40 | --- 41 | name: Include_example3 42 | description: Descriptor file with include section 43 | 44 | include: 45 | - /var/lib/workspace/teflo_data/.results/common-provision_results.yml 46 | 47 | orchestrate: 48 | . 49 | . 50 | . 51 | 52 | execute: 53 | . 54 | . 55 | . 56 | 57 | report: 58 | . 59 | . 60 | . 61 | 62 | --- 63 | name: Include_example4 64 | description: Descriptor file with include section 65 | 66 | include: 67 | - provision.yml 68 | - orchestrate.yml 69 | 70 | orchestrate: 71 | - name: ansible/ssh_connect.yml 72 | description: "setup key authentication between driver and clients" 73 | orchestrator: ansible 74 | hosts: driver 75 | ansible_options: 76 | skip_tags: 77 | - ssh_auth 78 | extra_vars: 79 | username: root 80 | password: redhat 81 | ansible_galaxy_options: 82 | role_file: roles.yml 83 | 84 | execute: 85 | . 86 | . 87 | . 88 | 89 | report: 90 | . 91 | . 92 | . 93 | --- 94 | name: Include_example5 95 | description: Descriptor file with include section 96 | 97 | include: 98 | - teflo/stack/provision_localhost.yml 99 | - teflo/stack/provision_libvirt.yml 100 | {% if true %} - teflo/stack/orchestrate-123.yml{% endif %} 101 | - teflo/stack/orchestrate.yml 102 | 103 | orchestrate: 104 | - name: ansible/ssh_connect.yml 105 | description: "setup key authentication between driver and clients" 106 | orchestrator: ansible 107 | hosts: driver 108 | ansible_options: 109 | skip_tags: 110 | - ssh_auth 111 | extra_vars: 112 | username: root 113 | password: redhat 114 | ansible_galaxy_options: 115 | role_file: roles.yml 116 | 117 | execute: 118 | . 119 | . 120 | . 121 | 122 | report: 123 | . 124 | . 125 | . 126 | --- 127 | name: remote_include_example 128 | description: include remote sdf from git server 129 | 130 | remote_workspace: 131 | - workspace_url: git@github.com:dno-github/remote-teflo-lib1.git 132 | alias_name: remote 133 | # the alias_name should not be the same as local folder, it will collide 134 | - workspace_url: https://github.com/dno-github/remote-teflo-lib1.git 135 | alias_name: remote2 136 | 137 | include: 138 | - "remote/sdf_remote.yml" 139 | 140 | name: sdf using remote include 141 | description: "Provision step" 142 | 143 | provision: 144 | - name: from_local_parent 145 | groups: localhost 146 | ip_address: 127.0.0.1 147 | ansible_params: 148 | ansible_connection: local 149 | 150 | 151 | execute: 152 | . 153 | . 154 | . 155 | 156 | report: 157 | . 158 | . 159 | . 160 | -------------------------------------------------------------------------------- /tests/functional/test_notification_emitter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_asset_provisioner 21 | 22 | Unit tests for testing teflo asset provisioner class. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | import mock 29 | import pytest 30 | 31 | from teflo.resources import Notification 32 | from teflo.core import NotificationPlugin 33 | from teflo.notifiers import Notifier 34 | 35 | 36 | @pytest.fixture(scope='class') 37 | def note_params(): 38 | params = dict(description='description', 39 | notifier='email-notifier', 40 | to='jsmith@email.com', 41 | subject='test') 42 | params['from'] = 'fbar@email.com' 43 | return params 44 | 45 | 46 | @pytest.fixture(scope='class') 47 | def plugin(): 48 | pg = mock.MagicMock(spec=NotificationPlugin, 49 | __plugin_name__='email-notifier') 50 | pg.notify = mock.MagicMock(return_value=[]) 51 | pg.validate = mock.MagicMock(return_value=[]) 52 | return pg 53 | 54 | 55 | @pytest.fixture(scope='class') 56 | def note(plugin, note_params): 57 | note = mock.MagicMock(spec=Notification, name='Test-Note') 58 | plugin.notification = note 59 | note.notifier = plugin 60 | return note 61 | 62 | 63 | @pytest.fixture(scope='class') 64 | def note_emitter(note): 65 | ne = Notifier(note) 66 | return ne 67 | 68 | 69 | class TestNotificationEmitter(object): 70 | 71 | @staticmethod 72 | def test_notification_emitter_constructor(note_emitter): 73 | assert isinstance(note_emitter, Notifier) 74 | 75 | @staticmethod 76 | def test_notification_emitter_notify(plugin, note_emitter): 77 | note_emitter.plugin = plugin 78 | note_emitter.notify() 79 | plugin.notify.assert_called() 80 | 81 | @staticmethod 82 | def test_notification_emitter_validate(plugin, note_emitter): 83 | note_emitter.plugin = plugin 84 | note_emitter.validate() 85 | plugin.validate.assert_called() 86 | 87 | @staticmethod 88 | def test_notification_emitter_notify_exception(plugin, note_emitter): 89 | plugin.notify.side_effect = Exception('Mock Notify Failure') 90 | note_emitter.plugin = plugin 91 | with pytest.raises(Exception): 92 | note_emitter.notify() 93 | 94 | @staticmethod 95 | def test_notification_emitter_validate_exception(plugin, note_emitter): 96 | plugin.validate.side_effect = Exception('Mock Validate Failure') 97 | note_emitter.plugin = plugin 98 | with pytest.raises(Exception): 99 | note_emitter.validate() -------------------------------------------------------------------------------- /examples/docs-usage/provision.yml: -------------------------------------------------------------------------------- 1 | --- 2 | provision: 3 | - name: ci_test_client_b 4 | groups: client, vnc 5 | provisioner: beaker-client 6 | 7 | --- 8 | provision: 9 | - name: ci_test_client_b 10 | groups: 11 | - client 12 | - vnc 13 | provisioner: beaker-client 14 | 15 | --- 16 | provision: 17 | - name: ci_test_client_b 18 | groups: 19 | - client 20 | - vnc 21 | provisioner: beaker-client 22 | 23 | --- 24 | name: common-provision 25 | description: 'common provisioning of resources used by the rest of the scenarios.' 26 | 27 | provision: 28 | - name: ci_test_client_b 29 | groups: 30 | - client 31 | - vnc 32 | provisioner: beaker-client 33 | 34 | --- 35 | name: common-provision 36 | description: 'common provisioning of resources used by the rest of the scenarios.' 37 | 38 | provision: 39 | - name: ci_test_client_a 40 | description: 41 | groups: 42 | - client 43 | - test_driver 44 | provisioner: linchpin-wrapper 45 | provider: 46 | count: 1 47 | credential: aws-creds 48 | name: aws 49 | region: us-east-2 50 | hostname: ec2-host.us-east-2.compute.amazonaws.com 51 | tx_id: 44 52 | keypair: ci_aws_key_pair 53 | node_id: i-0f452f3479919d703 54 | role: aws_ec2 55 | flavor: t2.nano 56 | image: ami-0d8f6eb4f641ef691 57 | ip_address: 58 | public: 13.59.32.24 59 | private: 172.31.33.91 60 | ansible_params: 61 | ansible_ssh_private_key_file: keys/ci_aws_key_pair.pem 62 | ansible_user: centos 63 | metadata: {} 64 | workspace: /home/dbaez/projects/teflo/e2e-acceptance-tests 65 | data_folder: /var/lib/workspace/teflo_data/fich6j1ooq 66 | 67 | # beaker scenario example 68 | --- 69 | 70 | name: beaker resource 71 | description: define a teflo host beaker resource to be provisioned 72 | 73 | provision: 74 | - name: beaker-node 75 | groups: node 76 | provisioner: beaker-client 77 | credential: beaker-creds 78 | arch: x86_64 79 | distro: RHEL-7.5 80 | variant: Server 81 | whiteboard: teflo beaker resource example 82 | jobgroup: '{{ jobgroup }}' 83 | username: '{{ username }}' 84 | password: '{{ password }}' 85 | host_requires_options: 86 | - "force={{ host_fqdn }}" 87 | ksappends: 88 | - | 89 | %post 90 | echo "This is my extra %post script" 91 | %end 92 | ssh_key: "keys/{{ key_name }}" 93 | ansible_params: 94 | ansible_user: root 95 | ansible_ssh_private_key_file: "keys/{{ key_name }}" 96 | 97 | # openstack scenario 98 | --- 99 | 100 | name: openstack resource 101 | description: define a teflo host openstack resource to be provisioned 102 | 103 | provision: 104 | - name: openstack-node 105 | groups: node 106 | provisioner: openstack-libcloud 107 | credential: openstack-creds 108 | image: rhel-7.5-server-x86_64-released 109 | flavor: m1.small 110 | networks: 111 | - '{{ network }}' 112 | floating_ip_pool: "10.8.240.0" 113 | keypair: '{{ keypair }}' 114 | server_metadata: 115 | provisioned_by: "teflo" 116 | build_url: "jenkins.com/build/123" 117 | ansible_params: 118 | ansible_user: cloud-user 119 | ansible_ssh_private_key_file: "keys/{{ keypair }}" 120 | 121 | # static scenario 122 | --- 123 | name: static resource 124 | description: define a static resource to be used throughout teflo 125 | 126 | provision: 127 | - name: static-node 128 | groups: node 129 | ip_address: 1.1.1.1 130 | ansible_params: 131 | ansible_user: root 132 | ansible_ssh_private_key_file: "keys/{{ key_name }}" 133 | -------------------------------------------------------------------------------- /examples/docs-usage/configuration.yml: -------------------------------------------------------------------------------- 1 | # teflo config file 2 | # ================== 3 | 4 | # the config file provides an additional way to define teflo parameters 5 | 6 | # config file is searched for in the following order below. a configuration 7 | # setting will be overrided if another source is found last 8 | # 1. /etc/teflo/teflo.cfg 9 | # 2. ./teflo.cfg (current working directory) 10 | # 3. TEFLO_SETTINGS (environment variable) 11 | 12 | # default settings 13 | 14 | [defaults] 15 | log_level=debug 16 | # Path for teflo's data folder where teflo logs will be stored 17 | data_folder=/var/local/teflo 18 | workspace=. 19 | # Endpoint URL of Cachet Status page 20 | # Cachet status page. 21 | resource_check_endpoint= 22 | # The teflo run exits on occurrence of a failure of a task in a scenario, if a user wants to continue 23 | # the teflo run, in spite of one task failure, the skip_fail parameter can be set to true in 24 | # the teflo.cfg or passed using cli. 25 | skip_fail=False 26 | # 27 | # A static inventory path can be used for ansible inventory file. 28 | # Can be relative path in teflo scenario workspace 29 | # inventory_folder=static/inventory 30 | # 31 | # Can be a directory in the user $HOME path 32 | # inventory_folder=~/scenario/static/inventory 33 | # 34 | # Can be an absolute path 35 | # inventory_folder=/test/scenario/static/inventory 36 | # 37 | # Can be a path containing an environment variable 38 | # inventory_folder=$WORKSPACE/scenario/static/inventory 39 | # default value of the inventory folder is 'TEFLO_DATA_FOLDER/.results/inventory' 40 | inventory_folder= 41 | # credentials file and Vault password 42 | # User can set all teh credential information in a text file and encrypt it using ansible vault 43 | # provide the path in under CREDENTIALS_PATH. Provide the vault password here. This password can be 44 | # exported as an environmental variable 45 | CREDENTIAL_PATH= 46 | VAULTPASS= 47 | 48 | 49 | # time out for each stage 50 | # you can set the timeout value for each of teflo's stages (validation, provision, orchestrate, execute, report and cleanup) 51 | [timeout] 52 | provision=500 53 | cleanup=1000 54 | orchestrate=300 55 | execute=200 56 | report=100 57 | validate=10 58 | 59 | 60 | # credentials settings 61 | 62 | [credentials:beaker-creds] 63 | hub_url= 64 | keytab= 65 | keytab_principal= 66 | username= 67 | password= 68 | 69 | [credentials:openstack-creds] 70 | auth_url= 71 | tenant_name= 72 | username= 73 | password= 74 | domain_name= 75 | 76 | # orchestrator settings 77 | 78 | [orchestrator:ansible] 79 | # remove ansible log 80 | log_remove=False 81 | # set the verbosity 82 | # this option will override the max verbosity when log level is set to debug. 83 | verbosity=vv 84 | 85 | [task_concurrency] 86 | # this controls how tasks (provision, orchestrate, execute, report) are executed 87 | # by Teflo either parallel or sequential. 88 | # When set to False the task will execute sequentially. 89 | provision=False 90 | 91 | 92 | # executor settings 93 | 94 | [executor:runner] 95 | # set the testrun_results to false if you dont want it to be collected in the logs for the xml files collected during 96 | # execution 97 | testrun_results=False 98 | # Teflo by default will NOT exit if the collection of artifact task fails. In order to exit the run on an error during 99 | # collection of artifacts user can set this field to true , else False or ignore the field. 100 | exit_on_error=True 101 | 102 | # Teflo Alias 103 | [alias] 104 | dev_run=run -s scenario.yml --log-level debug --iterate-method by_depth 105 | prod_run=show -s scenario.yml --list-labels 106 | -------------------------------------------------------------------------------- /teflo/tasks/cleanup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | teflo.tasks.cleanup 20 | 21 | Here you add brief description of what this module is about 22 | 23 | :copyright: (c) 2022 Red Hat, Inc. 24 | :license: GPLv3, see LICENSE for more details. 25 | """ 26 | from ..core import TefloTask 27 | from ..exceptions import TefloOrchestratorError 28 | from ..provisioners import AssetProvisioner 29 | from teflo.orchestrators import ActionOrchestrator 30 | 31 | 32 | class CleanupTask(TefloTask): 33 | """Cleanup task.""" 34 | __concurrent__ = False 35 | __task_name__ = 'cleanup' 36 | 37 | def __init__(self, msg, asset=None, package=None, **kwargs): 38 | """Constructor. 39 | 40 | :param msg: task message 41 | :type msg: str 42 | :param asset: asset reference 43 | :type asset: object 44 | :param package: package reference 45 | :type package: object 46 | :param kwargs: additional keyword arguments 47 | :type kwargs: dict 48 | """ 49 | super(CleanupTask, self).__init__(**kwargs) 50 | 51 | # set attributes 52 | self.msg = msg 53 | self.asset = asset 54 | self.package = package 55 | 56 | def _get_orchestrator_instance(self): 57 | """Get the orchestrator instance to perform clean up actions with. 58 | 59 | :return: orchestrator class instance 60 | :rtype: object 61 | """ 62 | # set package attributes to get actual asset objects over strings 63 | cleanup = getattr(self.package, 'cleanup') 64 | setattr(cleanup, 'all_hosts', getattr(self.package, 'all_hosts')) 65 | setattr(cleanup, 'hosts', getattr(self.package, 'hosts')) 66 | 67 | # create the orchestrator plugin object 68 | return ActionOrchestrator(cleanup) 69 | 70 | def run(self): 71 | """Run. 72 | 73 | This method is the main entry point to the task. 74 | """ 75 | self.logger.info(self.msg) 76 | 77 | # **** TASKS BELOW ONLY SHOULD BE RELATED TO THE ORCHESTRATOR **** 78 | if self.package and getattr(self.package, 'cleanup') is not None: 79 | # get the orchestrator to invoke 80 | orchestrator = self._get_orchestrator_instance() 81 | 82 | # perform final system configuration against test systems 83 | try: 84 | getattr(orchestrator, 'run')() 85 | except TefloOrchestratorError: 86 | self.logger.warning( 87 | 'Errors raised during cleanup orchestrate tasks are ' 88 | 'silenced. This allows all tasks to run through their ' 89 | 'cleanup tasks.' 90 | ) 91 | 92 | # **** TASKS BELOW ONLY SHOULD BE RELATED TO THE PROVISIONER **** 93 | if self.asset: 94 | if not getattr(self.asset, 'is_static'): 95 | provisioner = AssetProvisioner(self.asset) 96 | # teardown the asset 97 | getattr(provisioner, 'delete')() 98 | else: 99 | self.logger.warning('Asset %s is static, skipping teardown.' % 100 | getattr(self.asset, 'name')) 101 | -------------------------------------------------------------------------------- /tests/functional/test_exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | """ 20 | tests.test_exceptions 21 | 22 | Unit tests for testing teflo custom exceptions. 23 | 24 | :copyright: (c) 2022 Red Hat, Inc. 25 | :license: GPLv3, see LICENSE for more details. 26 | """ 27 | 28 | import pytest 29 | 30 | from teflo.exceptions import TefloError, TefloTaskError, \ 31 | TefloResourceError, TefloProvisionerError, TefloProviderError, \ 32 | TefloOrchestratorError, HelpersError, LoggerMixinError, \ 33 | TefloActionError, TefloExecuteError, TefloHostError, TefloReportError, \ 34 | ScenarioError, BeakerProvisionerError, OpenstackProviderError, \ 35 | OpenshiftProvisionerError, ArchiveArtifactsError 36 | 37 | 38 | def test_teflo_error(): 39 | with pytest.raises(TefloError): 40 | raise TefloError('error message') 41 | 42 | 43 | def test_teflo_task_error(): 44 | with pytest.raises(TefloTaskError): 45 | raise TefloTaskError('error message') 46 | 47 | 48 | def test_teflo_resource_error(): 49 | with pytest.raises(TefloResourceError): 50 | raise TefloResourceError('error message') 51 | 52 | 53 | def test_teflo_provisioner_error(): 54 | with pytest.raises(TefloProvisionerError): 55 | raise TefloProvisionerError('error message') 56 | 57 | 58 | def test_teflo_provider_error(): 59 | with pytest.raises(TefloProviderError): 60 | raise TefloProviderError('error message') 61 | 62 | 63 | def test_teflo_orchestrator_error(): 64 | with pytest.raises(TefloOrchestratorError): 65 | raise TefloOrchestratorError('error message') 66 | 67 | 68 | def test_teflo_helpers_error(): 69 | with pytest.raises(HelpersError): 70 | raise HelpersError('error message') 71 | 72 | 73 | def test_teflo_logger_mixin_error(): 74 | with pytest.raises(LoggerMixinError): 75 | raise LoggerMixinError('error message') 76 | 77 | 78 | def test_teflo_action_error(): 79 | with pytest.raises(TefloActionError): 80 | raise TefloActionError('error message') 81 | 82 | 83 | def test_teflo_execute_error(): 84 | with pytest.raises(TefloExecuteError): 85 | raise TefloExecuteError('error message') 86 | 87 | 88 | def test_teflo_host_error(): 89 | with pytest.raises(TefloHostError): 90 | raise TefloHostError('error message') 91 | 92 | 93 | def test_teflo_report_error(): 94 | with pytest.raises(TefloReportError): 95 | raise TefloReportError('error message') 96 | 97 | 98 | def test_scenario_error(): 99 | with pytest.raises(ScenarioError): 100 | raise ScenarioError('error message') 101 | 102 | 103 | def test_beaker_provisioner_error(): 104 | with pytest.raises(BeakerProvisionerError): 105 | raise BeakerProvisionerError('error message') 106 | 107 | 108 | def test_openstack_provider_error(): 109 | with pytest.raises(OpenstackProviderError): 110 | raise OpenstackProviderError('error message') 111 | 112 | 113 | def test_openshift_provisioner_error(): 114 | with pytest.raises(OpenshiftProvisionerError): 115 | raise OpenshiftProvisionerError('error message') 116 | 117 | 118 | def test_archive_artifacts_error(): 119 | with pytest.raises(ArchiveArtifactsError): 120 | raise ArchiveArtifactsError('error message') 121 | -------------------------------------------------------------------------------- /docs/users/definitions/report.rst: -------------------------------------------------------------------------------- 1 | Report 2 | ====== 3 | 4 | Overview 5 | -------- 6 | 7 | Teflo's report section declares which test artifacts collected during execution 8 | are to be imported into a Report & Analysis system. The input for artifact import 9 | will depend on the destination system. 10 | 11 | First, let's go over the basic structure that defines a Report resource. 12 | 13 | .. code-block:: yaml 14 | 15 | --- 16 | report: 17 | - name: 18 | description: 19 | executes: 20 | importer: 21 | 22 | .. important:: 23 | The Reporting systems currently supported are Polarion and Report Portal. These systems 24 | can be accessed using teflo's plugins **teflo_polarion_plugin** and **teflo_rppreproc_plugin** 25 | These plugins are only available for internal RedHat use at this time. Users can put 26 | in tickets `here `_ for new plugin development 27 | or contribute towards this effort. 28 | Please refer `Developers Guide <../../developers/development.html#how-to-write-an-plugin-for-teflo>`__ 29 | on how to contribute towards the plugin. 30 | 31 | 32 | .. list-table:: 33 | :widths: auto 34 | :header-rows: 1 35 | 36 | * - Key 37 | - Description 38 | - Type 39 | - Required 40 | 41 | * - name 42 | - The name of the test artifact to import. This can be a 43 | full name of an artifact, a shell pattern matching string, or 44 | a string using Teflo's data-passthru mechanism 45 | - String 46 | - True 47 | 48 | * - description 49 | - A description of the artifact being imported 50 | - String 51 | - False 52 | 53 | * - executes 54 | - The name of the execute block that collected 55 | the artifact. 56 | - List 57 | - False 58 | 59 | * - importer 60 | - The name of the importer to perform the import process. 61 | - String 62 | - True 63 | 64 | Executes 65 | -------- 66 | Defining a Teflo execute resource is optional. Teflo uses the execute resource 67 | for two reasons: 68 | 69 | * It uses the **artifact_locations** key as a quick way to check if the artifact 70 | being requested was collected and where to find it. 71 | 72 | * It uses the Asset resources assigned to the Execute to perform the internal 73 | templating if a data-passthru string is being used in the name key 74 | as search criteria. 75 | 76 | .. _finding_artifacts: 77 | 78 | Finding the right artifacts 79 | --------------------------- 80 | 81 | As noted in the table, the driving input will be the name key. 82 | The name can be a string defining the exact file/folder name, 83 | a shell matching pattern, or a teflo data-passthru pattern. 84 | Depending on the pattern used it will narrow or widen the search 85 | scope of the search. How teflo performs the search is by the following 86 | 87 | * Check if an execute resource was defined with the **execute** 88 | and then check **artifact_locations** key is defined for 89 | the execute in the execute section. 90 | 91 | * If there is an **execute** key and the artifact is listed as 92 | an item that was collected in the **artifact_locations** key, teflo 93 | will immediately validate the location. 94 | 95 | * If no **execute** key is defined, or an execute with no **artifact_location** 96 | key is used, or the artifacts is not shown as one of the items contained in the 97 | the artifact_location key, or the item location in the artifact_location key is 98 | no longer valid, it proceeds to walk the *data_folder/.results* folder. 99 | 100 | * If no artifacts are found after walking the *data_folder/.results*, teflo will abort the 101 | import process. 102 | 103 | * If artifacts are found, the list of artifacts will be processed and imported into 104 | the respective reporting system. 105 | 106 | More information on artifact_locations key refer :ref:`Finding Locations ` 107 | 108 | 109 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | """ 19 | Test Execution Framework Libraries and Objects (TEFLO) an orchestration software. 20 | """ 21 | import os 22 | import re 23 | import io 24 | 25 | from setuptools import setup, find_packages 26 | 27 | ROOT = os.path.dirname(__file__) 28 | VERSION_RE = re.compile(r'''__version__ = ['"]([a-zA-Z0-9.]+)['"]''') 29 | 30 | 31 | def get_version(): 32 | init = open(os.path.join(ROOT, 'teflo', '__init__.py')).read() 33 | return VERSION_RE.search(init).group(1) 34 | 35 | 36 | # reading description from README.rst 37 | with io.open(os.path.join(ROOT, 'README.rst'), encoding='utf-8') as f: 38 | long_description = f.read() 39 | 40 | 41 | setup( 42 | name='teflo', 43 | version=get_version(), 44 | license='GPLv3', 45 | author='Red Hat Inc.', 46 | description='Test Execution Framework Libraries and Objects. It is an orchestration software that controls the flow of a set of testing scenarios.', 47 | long_description=long_description, 48 | packages=find_packages(exclude=['tests*']), 49 | include_package_data=True, 50 | zip_safe=False, 51 | python_requires=">=3.9", 52 | install_requires=[ 53 | 'ansible>=2.14.0', 54 | 'apache-libcloud==2.2.0', 55 | "blaster>=0.3.0", 56 | 'Click>=6.7', 57 | 'ipaddress', 58 | 'Jinja2>=2.10', 59 | 'pykwalify>=1.6.0', 60 | 'python-cachetclient', 61 | 'ruamel.yaml>=0.15.64', 62 | 'paramiko>=2.4.2', 63 | 'retry2>=0.9.4', 64 | 'ssh-python>=0.9.0', 65 | 'requests>=2.20.1', 66 | 'urllib3>=1.26', 67 | 'termcolor>=1.1.0' 68 | ], 69 | extras_require={ 70 | 'linchpin-wrapper': ['teflo_linchpin_plugin'], 71 | 'openstack-client-plugin': ['teflo_openstack_client_plugin'], 72 | 'terraform-plugin': ['teflo-terraform-plugin'], 73 | 'webhook-notification-plugin': ['teflo-webhooks-notification-plugin'], 74 | 'notify-service-plugin': ['teflo-notify-service-plugin'] 75 | 76 | }, 77 | classifiers=[ 78 | 'Development Status :: 5 - Production/Stable', 79 | 'Intended Audience :: Developers', 80 | 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 81 | 'Natural Language :: English', 82 | 'Programming Language :: Python :: 3', 83 | 'Programming Language :: Python :: 3 :: Only', 84 | 'Programming Language :: Python :: 3.9', 85 | ], 86 | entry_points={ 87 | 'console_scripts': ['teflo=teflo.cli:teflo'], 88 | 'provider_plugins': [ 89 | 'aws_provider = teflo.providers:AwsProvider', 90 | 'beaker_provider = teflo.providers:BeakerProvider', 91 | 'libvirt_provider = teflo.providers:LibvirtProvider', 92 | 'openstack_provider = teflo.providers:OpenstackProvider' 93 | ], 94 | 'provisioner_plugins': [ 95 | 'beaker_client = teflo.provisioners.ext:BeakerClientProvisionerPlugin', 96 | 'openstack_libcloud = teflo.provisioners.ext:OpenstackLibCloudProvisionerPlugin' 97 | ], 98 | 'orchestrator_plugins': [ 99 | 'ansible = teflo.orchestrators.ext:AnsibleOrchestratorPlugin' 100 | ], 101 | 'executor_plugins': [ 102 | 'runner = teflo.executors.ext:AnsibleExecutorPlugin' 103 | ], 104 | 'notification_plugins': [ 105 | 'email-notifier = teflo.notifiers.ext:EmailNotificationPlugin' 106 | ] 107 | 108 | } 109 | ) 110 | -------------------------------------------------------------------------------- /docs/glossary.rst: -------------------------------------------------------------------------------- 1 | Glossary 2 | ======== 3 | 4 | .. glossary:: 5 | Ansible 6 | Open source software that automates software provisioning, 7 | configuration management, and application deployment. 8 | `Ansible `_ 9 | 10 | beaker 11 | Resource management and automated testing environment. 12 | 13 | Cachet 14 | An open source status page system. `Cachet `_ 15 | 16 | teflo 17 | Test Execution Framework Libraries and Onjects 18 | 19 | credentials (section) 20 | Required credential definitions for each resource that needs to be 21 | provisioned. Credentials are set in teflo.cfg file. They are 22 | referenced by name in the scenario. 23 | 24 | dnf 25 | A software package manager that installs, updates, and removes packages 26 | on RPM-based Linux distributions. 27 | 28 | E2E 29 | end to end 30 | 31 | execute (section) 32 | Defines the location, setup, execution and collection of results and 33 | artifacts of tests to be executed for a scenario. 34 | 35 | git 36 | A version-control system for tracking changes in computer files and 37 | coordinating work on those files among multiple people. 38 | 39 | Jenkins 40 | Open source automation server, Jenkins provides hundreds of plugins to 41 | support building, deploying and automating any project. 42 | `Jenkins `_ 43 | 44 | orchestrate (section) 45 | Defines the configuration and setup to be performed on the resources of 46 | a scenario in order to test the system properly. 47 | 48 | pip 49 | A package management system used to install and manage software packages 50 | written in Python. 51 | 52 | provision (section) 53 | Defines a list of resources and there inputs to be provisioned. 54 | 55 | PyPI 56 | The Python Package Index (PyPI) is a repository of software for the Python 57 | programming language. 58 | 59 | report (section) 60 | Defines the reporting mechanism of a scenario. 61 | 62 | resource (teflo) 63 | A host/node to provision or take action on. 64 | 65 | resource (external) 66 | External components that a scenario requires to run. 67 | 68 | resource check (section) 69 | Specifies a list of external resource components to check status of before 70 | running scenario. If any component not available the scenario will not run. 71 | 72 | role (ansible) 73 | Ways of automatically loading certain vars_files, tasks, and handlers based 74 | on a known file structure. Grouping content by roles allows easy sharing of 75 | roles with other users. 76 | 77 | groups (teflo) 78 | The function assumed or part played by a node/host. Specified in provision 79 | section. 80 | 81 | section (teflo) 82 | The major areas a scenario is broken into. Sections of a scenario relate to a 83 | particular component within teflo. Valid sections are 'Resource Check', 84 | Credentials, Provision, Orchestrate, Execute and Report. 85 | 86 | scenario (teflo) 87 | A teflo scenario descriptor file. Teflo input file. SDF. 88 | 89 | SDF 90 | scenario descriptor file 91 | 92 | task 93 | An action to be performed. 94 | 95 | task (ansible) 96 | A call to an ansible module. 97 | 98 | task (teflo) 99 | Actions that are run against a scenario. Valid tasks are validate, provision 100 | orchestrate, execute, report and cleanup. 101 | 102 | task (orchestrate) 103 | A configuration action that will then correlate to an orchestrators task. 104 | The default orchestrator for teflo is Ansible. 105 | 106 | tox 107 | A generic virtualenv management and test command line tool. 108 | 109 | virtualenv 110 | A tool to create isolated Python environments. 111 | `Virtualenv `_ 112 | 113 | YAML 114 | A human-readable data serialization language. It is commonly used for 115 | configuration files, but could be used in many applications where data is 116 | being stored or transmitted. 117 | 118 | yum 119 | Yellowdog Updater, Modified (YUM) is an open-source command-line 120 | package-management utility for computers running the GNU/Linux 121 | operating system using the RPM Package Manager 122 | 123 | -------------------------------------------------------------------------------- /teflo/importers/artifact_importer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2022 Red Hat, Inc. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from ..core import LoggerMixin, TimeMixin 20 | from ..exceptions import TefloImporterError 21 | from ..helpers import find_artifacts_on_disk, DataInjector 22 | 23 | 24 | class ArtifactImporter(LoggerMixin, TimeMixin): 25 | 26 | __importer_name__ = 'artifact-importer' 27 | 28 | def __init__(self, report): 29 | 30 | self.report = report 31 | self.artifact_paths = [] 32 | self.plugin = getattr(self.report, 'importer_plugin')(report) 33 | 34 | # check if user specified data pass-through injection 35 | if self.report.executes: 36 | # report.executes exist then look for host_list 37 | host_list = [host for execute in self.report.executes for host in execute.all_hosts] 38 | self.injector = DataInjector(host_list) 39 | else: 40 | # Assume no executes is assigned, so the helper 41 | # method fetch_executes added an attribute 'all_hosts' 42 | # to the report object 43 | self.injector = DataInjector(self.report.all_hosts) 44 | 45 | self.report_name = self.injector.inject(self.report.name) 46 | 47 | def validate_artifacts(self): 48 | 49 | # Check report has any executes associated. If not, proceed 50 | # to walk the data directory on disk. 51 | art_paths = [] 52 | self.logger.debug(self.report_name) 53 | if getattr(self.report, 'executes'): 54 | for execute in getattr(self.report, 'executes'): 55 | # check that the execute object collected artifacts 56 | if not execute.artifact_locations: 57 | self.logger.warning('The specified execute, %s, does not have any artifacts ' 58 | 'with it.' % execute.name) 59 | self.artifact_paths.extend(find_artifacts_on_disk 60 | (data_folder=self.report.config.get('RESULTS_FOLDER'), 61 | report_name=self.report_name)) 62 | else: 63 | self.artifact_paths.extend(find_artifacts_on_disk 64 | (data_folder=self.report.config.get('RESULTS_FOLDER'), 65 | report_name=self.report_name, 66 | art_location=self.injector.inject_list(execute.artifact_locations) 67 | ) 68 | ) 69 | else: 70 | self.artifact_paths.extend(find_artifacts_on_disk(data_folder=self.report.config.get('RESULTS_FOLDER'), 71 | report_name=self.report_name)) 72 | if not self.artifact_paths: 73 | raise TefloImporterError('No artifact could be found on the Teflo controller data folder.') 74 | 75 | def import_artifacts(self): 76 | self.plugin.artifacts = self.artifact_paths 77 | try: 78 | results = self.plugin.import_artifacts() 79 | if results: 80 | setattr(self.report, 'import_results', results) 81 | except Exception as ex: 82 | self.logger.error(ex) 83 | if getattr(self.plugin, 'import_results') == [None]: 84 | setattr(self.report, 'import_results', []) 85 | else: 86 | setattr(self.report, 'import_results', getattr(self.plugin, 'import_results')) 87 | raise TefloImporterError('Failed to import artifact %s' % self.report.name) 88 | 89 | def validate(self): 90 | """ 91 | validate the params provided are supported by the plugin 92 | :return: 93 | """ 94 | try: 95 | self.plugin.validate() 96 | except Exception: 97 | raise 98 | else: 99 | self.logger.info('successfully validated scenario Report against the schema!') 100 | -------------------------------------------------------------------------------- /docs/users/configuration.rst: -------------------------------------------------------------------------------- 1 | Configure Teflo 2 | ================ 3 | 4 | This is a mandatory configuration file, where you set your credentials, and 5 | there are many optional settings to help you adjust your usage of Teflo. 6 | The credentials of the configuration file is the only thing that 7 | is mandatory. Most of the other default configuration settings should be 8 | sufficient; however, please read through the options you have. 9 | 10 | Where it is loaded from (using precedence low to high): 11 | 12 | #. /etc/teflo/teflo.cfg 13 | #. ./teflo.cfg (current working directory) 14 | #. TEFLO_SETTINGS environment variable to the location of the file 15 | 16 | .. important:: 17 | 18 | It is important to realize if you have a configuration file set using 19 | both options, the configuration files will be combined, and common 20 | key values will be overridden by the higher precedent option, which will 21 | be the TEFLO_SETTINGS environment variable. 22 | 23 | Configuration example (with all options): 24 | 25 | .. literalinclude:: ../../examples/docs-usage/configuration.yml 26 | 27 | 28 | .. note:: 29 | 30 | Many of the configuration options can be overridden by passing cli options when running 31 | teflo. See the options in the running teflo `example. `__ 32 | 33 | Using Jinja Variable Data 34 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | 36 | Teflo uses Jinja2 template engine to be able to template variables 37 | within the teflo.cfg file. Teflo allows template variable data to be 38 | set as environmental variables 39 | 40 | Here is an example teflo.cfg file using Jinja to template some variable data: 41 | 42 | .. code-block:: bash 43 | 44 | [credentials:openstack] 45 | auth_url= 46 | username={{ OS_USER }} 47 | password={{ OS_PASSWORD }} 48 | tenant_name={{ OS_TENANT }} 49 | domain_name=redhat.com 50 | 51 | [task_concurrency] 52 | provision=True 53 | report=False 54 | orchestrate={{ ORC_TASK_CONCURRENCY }} 55 | 56 | Prior to running teflo, the templated variables will have to be exported 57 | 58 | .. code-block:: bash 59 | 60 | export OS_USER=user1 61 | export OS_PASSWORD=password 62 | export OS_TENANT=project1 63 | export ORC_TASK_CONCURRENCY=True 64 | 65 | 66 | 67 | inventory_folder 68 | ~~~~~~~~~~~~~~~~ 69 | 70 | The **inventory_folder** option is not a required option but it is important enough to note its usage. 71 | By default teflo will create an inventory directory containing ansible inventory files in its data 72 | directory. These are used during orchestration and execution. Refer to the `Teflo Output `__ 73 | page. 74 | 75 | Some times this is not desired behavior. This option allows a user to specify a static known directory 76 | that Teflo can use to place the ansible inventory files. If the specified directory does not exist, 77 | teflo will create it and place the ansible inventory files. If it does, teflo will only place the 78 | ansible files in the directory. Teflo will then use this static directory during orchestrate and execution. 79 | 80 | task_concurrency 81 | ~~~~~~~~~~~~~~~~ 82 | 83 | The **task_concurrency** option is used to control how tasks are executed by Teflo. Whether it should be sequential 84 | or in parallel/concurrent. Below is the default execution type of each of the Teflo tasks: 85 | 86 | .. list-table:: 87 | :widths: auto 88 | :header-rows: 1 89 | 90 | * - Key 91 | - Concurrent 92 | - Type 93 | 94 | * - validate 95 | - True 96 | - String 97 | 98 | * - provision 99 | - True 100 | - String 101 | 102 | * - orchestrate 103 | - False 104 | - String 105 | 106 | * - execute 107 | - False 108 | - String 109 | 110 | * - report 111 | - False 112 | - String 113 | 114 | There are cases where it makes sense to adjust the execution type. Below are some examples: 115 | 116 | There are cases when provisioning assets of different types that there might be an inter-dependency so executing 117 | the tasks in parallel will not suffice, i.e. provision a virtual network and a VM attached to that network. 118 | In that case, set the **provision=False** and arrange the assets in the scenario descriptor file in 119 | the proper sequential order. 120 | 121 | There are cases when you need to import the same test artifact into separate reporting systems but one reporting 122 | systems needs the data in the test artifact to be modified with metadata before it can be imported. 123 | i.e modify and import into Polarion with Polarion metadata and then import that same artifact into Report Portal. 124 | In that case, set the **report=False** and arrange the resources defined in the scenario descriptor file in the 125 | proper sequential order. 126 | 127 | There could be a case where you would like to execute two different test suites concurrently because they have 128 | no dependency on each other or there is no affect to each other. In that case, set the **execute=True** to have 129 | them running concurrently. 130 | 131 | -------------------------------------------------------------------------------- /docs/users/variable_data.rst: -------------------------------------------------------------------------------- 1 | Using Jinja Variable Data 2 | ========================= 3 | 4 | Teflo uses Jinja2 template engine to be able to template variables 5 | within a scenario file. Teflo allows template variable data to be 6 | set as environmental variables as well as pass variable data via command line. 7 | 8 | You can also store the variable data in a file and provide the file path in teflo.cfg 9 | 10 | Here is an example scenario file using Jinja to template some variable data: 11 | 12 | .. code-block:: yaml 13 | 14 | --- 15 | 16 | name: linchpin_vars_example 17 | description: template example 18 | 19 | provision: 20 | - name: db2_dummy 21 | provisioner: linchpin-wrapper 22 | groups: example 23 | credential: openstack 24 | resource_group_type: openstack 25 | resource_definitions: 26 | - name: {{ name | default('database') }} 27 | role: os_server 28 | flavor: {{ flavor | default('m1.small') }} 29 | image: rhel-7.5-server-x86_64-released 30 | count: {{ count | default('1') }} 31 | keypair: test-keypair 32 | networks: 33 | - {{ networks | default('provider_net_ipv6_only') }} 34 | 35 | 36 | The variable data can now be passed in one of three ways. 37 | 38 | Raw JSON 39 | -------- 40 | 41 | You can pass in the data raw as a JSON dictionary 42 | 43 | .. code-block:: bash 44 | 45 | teflo run -s scenario.yml -t provision --vars-data '{"flavor": "m2.small", "name": "test"}' 46 | 47 | 48 | .. code-block:: bash 49 | 50 | teflo run -s scenario.yml -t provision --vars-data '{"flavor": "m2.small", "name": "test"}' 51 | --vars-data '{"count": "2"}' 52 | 53 | Variable File 54 | ------------- 55 | 56 | You can pass in a variable file in yaml format defining the variable data you need. The variable file 57 | needs to be placed in the teflo workspace as **var_file.yml** or as yaml files under **vars directory** 58 | 59 | User can also set **var_file** as a parameter in the **defaults section of teflo.cfg**. 60 | This way user can avoid passing variable data via command line at every run 61 | 62 | Following is the precedence of how Teflo looks for variable data: 63 | 64 | #. Via command line 65 | #. defaults section of teflo.cfg 66 | #. var_file.yml under the teflo workspace 67 | #. yml files under the directory vars under teflo workspace 68 | 69 | 70 | Below is an example of the contents of a variable file template_file.yaml. 71 | 72 | .. code-block:: yaml 73 | 74 | --- 75 | flavor: m2.small 76 | networks: provider_net_cci_5 77 | name: test 78 | 79 | You can pass in the variable file directly 80 | 81 | .. code-block:: bash 82 | 83 | teflo run -s scenario.yml -t provision --vars-data template_file.yml --vars-data '{"count": "2"}' 84 | 85 | If using teflo.cfg this can be set as below. The var_file param can be a path to the variable file or path to 86 | the directory where the variable file is stored. If Teflo identifies it a directory then recursively it looks for all 87 | files with .yml or .yaml extension within that directory. 88 | 89 | .. code-block:: bash 90 | 91 | [defaults] 92 | var_file=~/template_file.yml 93 | 94 | 95 | .. code-block:: bash 96 | 97 | [defaults] 98 | var_file=~/var_dir 99 | 100 | The above example will look like 101 | 102 | .. code-block:: bash 103 | 104 | teflo run -s scenario.yml -t provision 105 | 106 | Directory with multiple .yml files 107 | ----------------------------------- 108 | 109 | You can pass in a directory path containing multiple .yml files. 110 | The code will look for files ending with '.yml' 111 | 112 | .. code-block:: bash 113 | 114 | teflo run -s scenario.yml -t provision --vars-data ~/files_dir 115 | --vars-data '{"count": "2", "key": "val"}' 116 | 117 | 118 | Nested Variable Usage 119 | ---------------------- 120 | Currently teflo supports nested variable using any of above methods 121 | 122 | **Note**: 123 | The nested variable can only be string after parsing 124 | 125 | For example: 126 | 127 | A nested variable can look like below: 128 | 129 | #. nested_var: "hello" 130 | #. nested_var: {{ hey }} 131 | #. nested_var: "hello{{ hey }}" 132 | 133 | 134 | 135 | You can 136 | 137 | #. Use multiple layer nested vars 138 | .. code-block:: yaml 139 | 140 | name: {{ hello }} 141 | hello: {{ world }} 142 | world: {{ Hey }} 143 | Hey: "I'm a developer" 144 | 145 | #. Use multiple nested variables inside one filed 146 | .. code-block:: yaml 147 | 148 | name: "{{ hello }} {{ world }}" 149 | hello: "asd" 150 | world: {{ Hey }} 151 | Hey: "I'm a developer" 152 | 153 | #. Use nested variable in a list or dict 154 | .. code-block:: yaml 155 | 156 | name: 157 | Tom: {{ TomName }} 158 | Jack: {{ JackName }} 159 | TomName: "Tom Biden" 160 | JackName: "Jack Chen" 161 | adress: 162 | - {{ street }} 163 | - {{ city }} 164 | - {{ state }} 165 | street: "Boston Street" 166 | city: "Boston" 167 | state: "Massachusetts" 168 | 169 | .. note:: 170 | 171 | **TEFLO_DATA_FOLDER** , **TEFLO_RESULTS_FOLDER** and **TEFLO_WORKSPACE** are TEFLO 172 | environmental variables that are made available during a teflo run, 173 | which can be used in scripts and playbooks. They provide the absolute path for teflo's 174 | data folder, results folder and workspace respectively -------------------------------------------------------------------------------- /teflo/files/schema.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # default teflo schema 3 | 4 | type: map 5 | allowempty: True 6 | mapping: 7 | name: 8 | required: True 9 | type: str 10 | description: 11 | required: False 12 | type: str 13 | 14 | resource_check: 15 | allowempty: True 16 | type: map 17 | mapping: 18 | monitored_services: 19 | allowempty: True 20 | type: seq 21 | sequence: 22 | - type: str 23 | playbook: 24 | allowempty: True 25 | type: seq 26 | sequence: 27 | - type: map 28 | mapping: 29 | name: 30 | required: True 31 | type: str 32 | ansible_options: 33 | required: False 34 | type: any 35 | ansible_galaxy_options: 36 | allowempty: True 37 | type: map 38 | script: 39 | allowempty: True 40 | type: seq 41 | sequence: 42 | - type: map 43 | mapping: 44 | name: 45 | required: True 46 | type: str 47 | chdir: 48 | type: str 49 | creates: 50 | type: str 51 | decrypt: 52 | type: str 53 | executable: 54 | type: str 55 | removes: 56 | type: str 57 | warn: 58 | type: str 59 | stdin: 60 | type: str 61 | stdin_add_newline: 62 | type: str 63 | ansible_options: 64 | required: False 65 | type: any 66 | 67 | include: 68 | required: False 69 | type: any 70 | 71 | provision: 72 | required: False 73 | sequence: 74 | - type: map 75 | allowempty: True 76 | matching-rule: any 77 | func: check_provider_present 78 | mapping: 79 | name: 80 | required: True 81 | type: str 82 | description: 83 | type: str 84 | ip_address: 85 | required: False 86 | type: any 87 | provisioner: 88 | type: str 89 | required: False 90 | ansible_params: 91 | type: map 92 | allowempty: True 93 | labels: 94 | type: any 95 | func: type_str_list 96 | metadata: 97 | allowempty: True 98 | type: map 99 | credential: 100 | required: False 101 | type: str 102 | regex;(groups): 103 | required: False 104 | type: any 105 | func: type_str_list 106 | regex;(.*): 107 | required: False 108 | type: any 109 | 110 | orchestrate: 111 | required: False 112 | sequence: 113 | - type: map 114 | allowempty: True 115 | mapping: 116 | name: 117 | required: True 118 | type: str 119 | description: 120 | type: str 121 | orchestrator: 122 | type: str 123 | func: valid_orchestrator 124 | hosts: 125 | required: True 126 | type: any 127 | func: type_str_list 128 | labels: 129 | type: any 130 | func: type_str_list 131 | 132 | execute: 133 | required: False 134 | sequence: 135 | - type: map 136 | allowempty: True 137 | mapping: 138 | name: 139 | required: True 140 | type: str 141 | description: 142 | type: str 143 | executor: 144 | required: True 145 | type: str 146 | func: valid_executor 147 | hosts: 148 | required: True 149 | type: any 150 | func: type_str_list 151 | labels: 152 | type: any 153 | func: type_str_list 154 | 155 | report: 156 | required: False 157 | sequence: 158 | - type: map 159 | allowempty: True 160 | mapping: 161 | name: 162 | required: True 163 | type: any 164 | description: 165 | type: str 166 | executes: 167 | type: any 168 | func: type_str_list 169 | required: False 170 | provider: 171 | type: map 172 | allowempty: True 173 | mapping: 174 | name: 175 | required: True 176 | type: str 177 | importer: 178 | type: str 179 | labels: 180 | type: any 181 | func: type_str_list 182 | 183 | notifications: 184 | required: False 185 | sequence: 186 | - type: map 187 | allowempty: True 188 | mapping: 189 | name: 190 | type: str 191 | description: 192 | type: str 193 | notifier: 194 | required: True 195 | type: str 196 | on_start: 197 | required: False 198 | type: bool 199 | on_success: 200 | required: False 201 | type: bool 202 | on_failure: 203 | required: False 204 | type: bool 205 | on_demand: 206 | required: False 207 | type: bool 208 | on_tasks: 209 | required: False 210 | type: seq 211 | sequence: 212 | - type: str 213 | --------------------------------------------------------------------------------