├── inventories ├── user_plugins │ ├── cow.yaml │ ├── fox.yaml │ ├── README.md │ └── inventory_plugins │ │ ├── cow.py │ │ └── fox.py ├── bad.yml ├── create_100_hosts.ini ├── create_10_hosts.ini ├── create_500_hosts.ini ├── create_10000_hosts.ini ├── create_1000_hosts.ini ├── create_3600_hosts.ini ├── create_5000_hosts.ini ├── create_60000_hosts.ini ├── group_vars │ ├── group_one │ ├── group_four │ └── group_seven ├── linode_fqcn.linode.yml ├── invalid_inventory.ini ├── host_vars │ ├── group_one_host_01 │ ├── ungrouped_host_01 │ ├── group_four_host_01 │ └── group_seven_host_01 ├── more_inventories │ ├── group_vars │ │ ├── group_four │ │ ├── group_one │ │ └── group_seven │ ├── host_vars │ │ ├── group_four_host_01 │ │ ├── ungrouped_host_06 │ │ ├── group_one_host_01 │ │ └── group_seven_host_01 │ ├── even_more_inventories │ │ ├── group_vars │ │ │ ├── group_four │ │ │ ├── group_one │ │ │ └── group_seven │ │ ├── host_vars │ │ │ ├── ungrouped_host_11 │ │ │ ├── group_four_host_01 │ │ │ ├── group_one_host_01 │ │ │ └── group_seven_host_01 │ │ ├── inventory.ini │ │ └── dyn_inventory.py │ ├── inventory.ini │ └── dyn_inventory.py ├── script_migrations │ ├── bad_script_1.py │ ├── bad_script_2.py │ ├── bad_script_3.py │ ├── sleep_20s.py │ ├── sleep_2s.py │ ├── sleep_300s.py │ ├── stderr.py │ ├── large_5.py │ ├── large_5000.py │ ├── credential_file.py │ ├── ordering.py │ ├── ansible_host.py │ ├── large_dense.py │ ├── empty_group.py │ ├── large_sparse.py │ ├── bad_script_4.py │ ├── large_hostvars.py │ ├── test_limit.py │ ├── script_source.py │ ├── delete_group_3_custom_script.py │ ├── overwrite1.py │ ├── basic_structure.py │ ├── delete_group_2_custom_script.py │ ├── delete_group_1_custom_script.py │ ├── overwrite2.py │ ├── custom_script.py │ ├── encrypted_var.py │ └── test_isolation.py ├── constructed │ ├── group_vars │ │ ├── account_4321.yml │ │ └── account_1234.yml │ ├── north.ini │ ├── east.ini │ ├── south.ini │ ├── west.ini │ └── README.md ├── for_gen_host_status.ini ├── azure_rm.yml ├── aws_ec2.yml ├── openstack.yml ├── vmware.yml ├── gcp_compute.yml ├── dyn_inventory_sleep_60s.py ├── invalid_dyn_inventory.py ├── linode.yml ├── inventory.ini ├── dyn_inventory_test_env.py ├── collections │ └── ansible_collections │ │ └── shanemcd │ │ └── scratch │ │ └── plugins │ │ └── inventory │ │ └── blah.py ├── dyn_inventory_test_two_env.py ├── changes_slow.py ├── changes.py ├── dyn_inventory.py └── metaless_dyn_inventory.py ├── ansible.cfg ├── .gitignore ├── ping.yml ├── roles ├── test_tag_role │ └── tasks │ │ └── main.yml └── utf-8-䉪ቒ칸ⱷꯔ噂폄蔆㪗輥 │ └── tasks │ └── main.yml ├── ansible_env.yml ├── hello world.yml ├── utils ├── trigger_update.yml ├── multivault-dotted-vars.yml └── trigger_update.sh ├── pause.yml ├── clear_facts.yml ├── become.yml ├── run_command.yml ├── check.yml ├── debug_hostvars.yml ├── site.yml ├── test_collections ├── job │ ├── test_tower_job_list.j2 │ ├── test_tower_job_wait.j2 │ ├── test_tower_job_cancel.j2 │ └── test_tower_job_launch.j2 ├── test_tower_organization.j2 ├── test_tower_workflow_approval.j2 ├── test_tower_execution_environment.j2 ├── test_tower_inventory_source.j2 ├── test_tower_project.j2 ├── test_tower_job.j2 └── test_tower_job_template.j2 ├── debug_hostvars_inventory_hostname.yml ├── debug2.yml ├── test_include_role.yml ├── README.md ├── check_produce_inc_output.yml ├── debug_and_sleep.yml ├── gen_host_status_loop.yml ├── debug.yml ├── valid_yaml_invalid_ansible.yml ├── cat_file.yml ├── fail.yml ├── fail_unless.yml ├── gen_host_status.yml ├── file.yml ├── pass_unless.yml ├── collections └── ansible_collections │ └── testing │ └── indirect_host_counting │ ├── extension │ └── audit │ │ └── event_query.yml │ └── plugins │ └── action │ └── produce_inc_output.py ├── nested_debug.yml ├── long_running.yml ├── stress.yml ├── test_angular_var_bind.yml ├── chatty_tasks.yml ├── rax_credentials_test.yml ├── aws_credentials_test.yml ├── handler.yml ├── azure_credentials_test.yml ├── debug_var_list.yml ├── run_shell.yml ├── sleep.yml ├── cloud_modules ├── rhv.yml ├── k8s.yml ├── openstack.yml ├── tower.yml ├── aws.yml ├── vmware.yml ├── azure_rm.yml ├── gce.yml └── README.md ├── gce_credentials_test.yml ├── cidr_merge.yml ├── cat_files.yml ├── debug-loop.yml ├── rescued_not_failed.yml ├── chatty_payload.yml ├── test_tags_include.yml ├── debug_dynamic_variable.yml ├── debug_extra_vars.yml ├── custom_json.yml ├── patch_and_reboot.yml ├── gather_facts.yml ├── scan_custom.yml ├── read_file_content.yml ├── test_ansible_shell.yml ├── serial.yml ├── bursting_events.yml ├── vaulted_ansible_env.yml ├── environ_test.yml ├── custom_json_vars.yml ├── vault.yml ├── vaulted_debug_hostvars.yml ├── file_finder.yml ├── test_set_stats.yml ├── ping-20.yml ├── test_tags.yml ├── write_file_content.yml ├── tower_collection_smoke.yml ├── tower_collection_smoke.j2 ├── gather_facts_set_stats.yml ├── long_task_name.yml ├── gen_host_status_base.yml ├── async_tasks.yml ├── use_facts.yml ├── setfact_50.yml ├── multivault.yml ├── utf-8-䉪ቒ칸ⱷꯔ噂폄蔆㪗輥.yml ├── library └── test_scan_facts.py ├── test_proot.yml ├── free_waiter.yml ├── debug-50.yml ├── dynamic_inventory.yml ├── become_plugins └── custom_plugin.py └── LICENSE /inventories/user_plugins/cow.yaml: -------------------------------------------------------------------------------- 1 | plugin: cow -------------------------------------------------------------------------------- /inventories/user_plugins/fox.yaml: -------------------------------------------------------------------------------- 1 | plugin: fox -------------------------------------------------------------------------------- /inventories/bad.yml: -------------------------------------------------------------------------------- 1 | plugin: shanemcd.scratch.blah 2 | -------------------------------------------------------------------------------- /inventories/create_100_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:99] 2 | -------------------------------------------------------------------------------- /inventories/create_10_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:9] 2 | -------------------------------------------------------------------------------- /inventories/create_500_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:499] 2 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | deprecation_warnings=false 3 | -------------------------------------------------------------------------------- /inventories/create_10000_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:9999] 2 | -------------------------------------------------------------------------------- /inventories/create_1000_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:999] 2 | -------------------------------------------------------------------------------- /inventories/create_3600_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:3599] 2 | -------------------------------------------------------------------------------- /inventories/create_5000_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:4999] 2 | -------------------------------------------------------------------------------- /inventories/create_60000_hosts.ini: -------------------------------------------------------------------------------- 1 | test_host_[:59999] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | 3 | 4 | .idea 5 | /tower_collection_actual.yml -------------------------------------------------------------------------------- /inventories/group_vars/group_one: -------------------------------------------------------------------------------- 1 | group_one_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/linode_fqcn.linode.yml: -------------------------------------------------------------------------------- 1 | plugin: community.general.linode 2 | -------------------------------------------------------------------------------- /inventories/invalid_inventory.ini: -------------------------------------------------------------------------------- 1 | [syntax ?? error] 2 | not a host name 3 | -------------------------------------------------------------------------------- /inventories/group_vars/group_four: -------------------------------------------------------------------------------- 1 | group_four_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/group_vars/group_seven: -------------------------------------------------------------------------------- 1 | group_seven_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/host_vars/group_one_host_01: -------------------------------------------------------------------------------- 1 | group_one_host_01_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/host_vars/ungrouped_host_01: -------------------------------------------------------------------------------- 1 | ungrouped_host_01_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/group_vars/group_four: -------------------------------------------------------------------------------- 1 | group_four_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /ping.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - ping: 7 | -------------------------------------------------------------------------------- /roles/test_tag_role/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="{{ test_tag_role_msg | default('')}}" -------------------------------------------------------------------------------- /inventories/host_vars/group_four_host_01: -------------------------------------------------------------------------------- 1 | group_four_host_01_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/host_vars/group_seven_host_01: -------------------------------------------------------------------------------- 1 | group_seven_host_01_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/group_vars/group_one: -------------------------------------------------------------------------------- 1 | group_one_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/group_vars/group_seven: -------------------------------------------------------------------------------- 1 | group_seven_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /ansible_env.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | tasks: 5 | - debug: 6 | var: ansible_env 7 | -------------------------------------------------------------------------------- /hello world.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - ping: 7 | -------------------------------------------------------------------------------- /inventories/script_migrations/bad_script_1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | raise Exception("Fail!") 3 | -------------------------------------------------------------------------------- /utils/trigger_update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | tasks: 5 | - script: 'trigger_update.sh' -------------------------------------------------------------------------------- /inventories/more_inventories/host_vars/group_four_host_01: -------------------------------------------------------------------------------- 1 | group_four_host_01_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/host_vars/ungrouped_host_06: -------------------------------------------------------------------------------- 1 | ungrouped_host_06_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/script_migrations/bad_script_2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | 4 | sys.exit(1) 5 | -------------------------------------------------------------------------------- /pause.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - pause: seconds=1 7 | -------------------------------------------------------------------------------- /clear_facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - meta: clear_facts 7 | -------------------------------------------------------------------------------- /inventories/more_inventories/host_vars/group_one_host_01: -------------------------------------------------------------------------------- 1 | group_one_host_01_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/host_vars/group_seven_host_01: -------------------------------------------------------------------------------- 1 | group_seven_host_01_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /roles/utf-8-䉪ቒ칸ⱷꯔ噂폄蔆㪗輥/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - debug: msg="Task needed for role name to be displayed" 4 | -------------------------------------------------------------------------------- /become.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | become: yes 4 | tasks: 5 | - name: Become 6 | command: id 7 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/group_vars/group_four: -------------------------------------------------------------------------------- 1 | group_four_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/group_vars/group_one: -------------------------------------------------------------------------------- 1 | group_one_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/group_vars/group_seven: -------------------------------------------------------------------------------- 1 | group_seven_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /run_command.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: true 5 | tasks: 6 | - command: '{{command}}' 7 | -------------------------------------------------------------------------------- /inventories/script_migrations/bad_script_3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | 4 | print(json.dumps({})) 5 | -------------------------------------------------------------------------------- /check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | tasks: 5 | - name: 'Fail if not run with --check' 6 | shell: 'exit 1' 7 | -------------------------------------------------------------------------------- /debug_hostvars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | tasks: 5 | - debug: 6 | var: hostvars 7 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/host_vars/ungrouped_host_11: -------------------------------------------------------------------------------- 1 | ungrouped_host_11_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/constructed/group_vars/account_4321.yml: -------------------------------------------------------------------------------- 1 | account_owner: Shane 2 | account_number: 4321 3 | account_alias: sustaining 4 | -------------------------------------------------------------------------------- /inventories/for_gen_host_status.ini: -------------------------------------------------------------------------------- 1 | 1_ok 2 | 2_skipped 3 | 3_changed 4 | 4_failed 5 | 5_ignored 6 | 6_rescued 7 | 7_unreachable 8 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/host_vars/group_four_host_01: -------------------------------------------------------------------------------- 1 | group_four_host_01_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/host_vars/group_one_host_01: -------------------------------------------------------------------------------- 1 | group_one_host_01_should_not_have_this_var: True 2 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/host_vars/group_seven_host_01: -------------------------------------------------------------------------------- 1 | group_seven_host_01_should_have_this_var: True 2 | -------------------------------------------------------------------------------- /site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | tasks: 5 | - name: site | hello world 6 | shell: echo "Hi! Ansible is working" 7 | -------------------------------------------------------------------------------- /test_collections/job/test_tower_job_list.j2: -------------------------------------------------------------------------------- 1 | - name: list Job 2 | {{ collection_id }}.tower_job_list: 3 | register: list_job 4 | -------------------------------------------------------------------------------- /debug_hostvars_inventory_hostname.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - debug: 5 | var: hostvars[inventory_hostname] 6 | -------------------------------------------------------------------------------- /inventories/constructed/group_vars/account_1234.yml: -------------------------------------------------------------------------------- 1 | account_owner: Hao Liu 2 | account_number: 1234 3 | account_alias: product_dev 4 | -------------------------------------------------------------------------------- /debug2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - debug: msg='hello' 7 | - debug: msg='goodbye' 8 | -------------------------------------------------------------------------------- /test_include_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - include_role: 6 | name: test_tag_role 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ansible-playbooks 2 | ================= 3 | 4 | A collection of basic playbooks designed to aid in testing ansible functionality. 5 | -------------------------------------------------------------------------------- /check_produce_inc_output.yml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | gather_facts: false 3 | tasks: 4 | - testing.indirect_host_counting.produce_inc_output: -------------------------------------------------------------------------------- /inventories/azure_rm.yml: -------------------------------------------------------------------------------- 1 | plugin: azure_rm 2 | # azure_rm inventory plugin inventory, partial example 3 | # requires azure>=2.0.0 to be installed in venv to use 4 | -------------------------------------------------------------------------------- /test_collections/job/test_tower_job_wait.j2: -------------------------------------------------------------------------------- 1 | - name: wait Job 2 | {{ collection_id }}.tower_job_wait: 3 | job_id: {{ job_id }} 4 | register: wait_job 5 | -------------------------------------------------------------------------------- /debug_and_sleep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="{{ message_number|default(1) * message_size|default(1024) }}" 3 | - pause: seconds="{{ sleep_interval|default(1)|int }}" 4 | -------------------------------------------------------------------------------- /gen_host_status_loop.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | gather_facts: false 3 | tasks: 4 | - include: gen_host_status_base.yml 5 | loop: 6 | - 1 7 | - 2 8 | -------------------------------------------------------------------------------- /inventories/aws_ec2.yml: -------------------------------------------------------------------------------- 1 | plugin: aws_ec2 2 | # aws_ec2 inventory plugin inventory, partial example 3 | # boto3 must be installed in venv to successfully use plugin 4 | -------------------------------------------------------------------------------- /test_collections/job/test_tower_job_cancel.j2: -------------------------------------------------------------------------------- 1 | - name: cancel Job 2 | {{ collection_id }}.tower_job_cancel: 3 | job_id: {{ job_id }} 4 | register: cancel_job 5 | -------------------------------------------------------------------------------- /debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | connection: local 6 | vars: 7 | msg: 'hello' 8 | tasks: 9 | - debug: var=msg 10 | -------------------------------------------------------------------------------- /inventories/script_migrations/sleep_20s.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json, time 3 | 4 | time.sleep(20) 5 | inventory = dict() 6 | print(json.dumps(inventory)) 7 | -------------------------------------------------------------------------------- /inventories/script_migrations/sleep_2s.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json, time 3 | 4 | time.sleep(2) 5 | inventory = dict() 6 | print(json.dumps(inventory)) 7 | -------------------------------------------------------------------------------- /inventories/script_migrations/sleep_300s.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json, time 3 | 4 | time.sleep(300) 5 | inventory = dict() 6 | print(json.dumps(inventory)) 7 | -------------------------------------------------------------------------------- /inventories/openstack.yml: -------------------------------------------------------------------------------- 1 | plugin: openstack 2 | # openstack inventory plugin inventory, partial example 3 | # openstacksdk must be installed in venv to successfully use plugin 4 | -------------------------------------------------------------------------------- /inventories/script_migrations/stderr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from __future__ import print_function 3 | import sys 4 | 5 | print("TEST", file=sys.stderr) 6 | print("{}") 7 | -------------------------------------------------------------------------------- /test_collections/job/test_tower_job_launch.j2: -------------------------------------------------------------------------------- 1 | - name: launch Job 2 | {{ collection_id }}.tower_job_launch: 3 | job_template: {{ job_template }} 4 | register: launch_job 5 | -------------------------------------------------------------------------------- /valid_yaml_invalid_ansible.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | this_should_make_no_sense: | 4 | and indeed it does not. Because if it did, it would then 5 | make sense 6 | -------------------------------------------------------------------------------- /cat_file.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - command: 'cat {{ file_to_cat|default(ansible_env.AP_FILE_TO_CAT) }}' 5 | register: cat 6 | - debug: 7 | var: cat 8 | -------------------------------------------------------------------------------- /inventories/constructed/north.ini: -------------------------------------------------------------------------------- 1 | [account_1234] 2 | host2 state=reboot 3 | host4 4 | 5 | [account_4321] 6 | host3 7 | 8 | [accounts:children] 9 | account_1234 10 | account_4321 11 | -------------------------------------------------------------------------------- /fail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | vars: 5 | fail: true 6 | 7 | tasks: 8 | - fail: msg="Sorry, unless you tell me otherwise, this task will fail" 9 | when: fail 10 | -------------------------------------------------------------------------------- /fail_unless.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | vars: 5 | fail: true 6 | 7 | tasks: 8 | - fail: msg="Sorry, unless you tell me otherwise, this task will fail" 9 | when: fail 10 | -------------------------------------------------------------------------------- /gen_host_status.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | gather_facts: false 3 | tasks: 4 | - name: Run gen host status base tasks 5 | ansible.builtin.include_tasks: 6 | file: gen_host_status_base.yml 7 | -------------------------------------------------------------------------------- /file.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | vars: 6 | file_name: '/tmp/test' 7 | tasks: 8 | - file: 9 | path: '{{file_name}}' 10 | state: touch 11 | -------------------------------------------------------------------------------- /inventories/constructed/east.ini: -------------------------------------------------------------------------------- 1 | [account_1234] 2 | host1 3 | host2 state=shutdown 4 | 5 | [account_4321] 6 | host3 state=reboot 7 | 8 | [accounts:children] 9 | account_1234 10 | account_4321 11 | -------------------------------------------------------------------------------- /pass_unless.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | vars: 5 | fail: false 6 | 7 | tasks: 8 | - fail: msg="Congrats, you asked for this playbook to fail ... and it has" 9 | when: fail 10 | -------------------------------------------------------------------------------- /inventories/constructed/south.ini: -------------------------------------------------------------------------------- 1 | [account_1234] 2 | host1 3 | host2 state=shutdown 4 | 5 | [account_4321] 6 | host3 state=running 7 | 8 | [accounts:children] 9 | account_1234 10 | account_4321 11 | -------------------------------------------------------------------------------- /inventories/constructed/west.ini: -------------------------------------------------------------------------------- 1 | [account_1234] 2 | host4 3 | host6 state=shutdown 4 | 5 | [account_4321] 6 | host5 state=shutdown 7 | 8 | [accounts:children] 9 | account_1234 10 | account_4321 11 | -------------------------------------------------------------------------------- /inventories/vmware.yml: -------------------------------------------------------------------------------- 1 | plugin: vmware_vm_inventory 2 | # vmware inventory plugin inventory, partial example 3 | # PyVmomi, requests>=2.3, vsphere, vcloud must be installed in venv to successfully use plugin 4 | -------------------------------------------------------------------------------- /collections/ansible_collections/testing/indirect_host_counting/extension/audit/event_query.yml: -------------------------------------------------------------------------------- 1 | { 2 | "foo.bar.baz": {"query": "[.my_children | .[] | select(.changed == true)] | length", "category": "children"} 3 | } -------------------------------------------------------------------------------- /nested_debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | connection: local 6 | vars: 7 | msg: 'hello' 8 | tasks: 9 | - command: 'ansible-playbook -i localhost, debug.yml' 10 | -------------------------------------------------------------------------------- /inventories/gcp_compute.yml: -------------------------------------------------------------------------------- 1 | plugin: gcp_compute 2 | projects: 3 | - ansible-tower-engineering 4 | # google cloud inventory plugin inventory, partial example 5 | # requires google-auth library in python environment 6 | -------------------------------------------------------------------------------- /long_running.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: 'Test playbook that sleeps for long so there's time to cancel it' 4 | hosts: all 5 | gather_facts: false 6 | 7 | tasks: 8 | - name: sleep for long 9 | command: sleep 100000 10 | -------------------------------------------------------------------------------- /stress.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | vars: 6 | stress_args: "--vm 16 --vm-bytes 1024M --timeout 60" 7 | tasks: 8 | - name: "Run stress command" 9 | command: "stress {{ stress_args }}" 10 | -------------------------------------------------------------------------------- /test_angular_var_bind.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: 'Test that curly braces "{" in task names' 3 | hosts: all 4 | tasks: 5 | - name: "Username is '{{username | default(ansible_env['SUDO_USER'])}}'" 6 | debug: msg="{{ansible_env['SUDO_USER']}}" 7 | -------------------------------------------------------------------------------- /chatty_tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | vars: 6 | num_messages: 50 7 | tasks: 8 | - debug: 9 | msg: "This is a debug message: {{ item }}" 10 | with_sequence: 'count={{ num_messages }}' 11 | -------------------------------------------------------------------------------- /rax_credentials_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Tests whether two environment variables are present (and non-empty) 4 | 5 | - hosts: local 6 | connection: local 7 | tasks: 8 | - shell: 'test -n "${RAX_USERNAME}"' 9 | - shell: 'test -n "${RAX_API_KEY}"' 10 | -------------------------------------------------------------------------------- /aws_credentials_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Tests whether two environment variables are present (and non-empty) 4 | 5 | - hosts: local 6 | connection: local 7 | tasks: 8 | - shell: 'test -n "${AWS_ACCESS_KEY}"' 9 | - shell: 'test -n "${AWS_SECRET_KEY}"' 10 | -------------------------------------------------------------------------------- /handler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | tasks: 5 | - name: task with status "changed" 6 | command: /bin/true 7 | changed_when: true 8 | notify: handler 9 | handlers: 10 | - name: handler 11 | command: /bin/true 12 | -------------------------------------------------------------------------------- /inventories/script_migrations/large_5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | 4 | 5 | data = {"_meta": {"hostvars": {}}} 6 | 7 | for i in range(5): 8 | data.setdefault("ungrouped", []).append("Host-{}".format(i)) 9 | 10 | print(json.dumps(data, indent=2)) 11 | -------------------------------------------------------------------------------- /azure_credentials_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Tests whether two environment variables are present (and non-empty) 4 | 5 | - hosts: local 6 | connection: local 7 | tasks: 8 | - shell: 'test -n "${AZURE_SUBSCRIPTION_ID}"' 9 | - shell: 'test -n "${AZURE_CERT_PATH}"' 10 | -------------------------------------------------------------------------------- /debug_var_list.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | vars: 6 | first: 'one' 7 | second: 'fine' 8 | third: 'day' 9 | results: ['{{ first }}', '{{ second }}', '{{ third }}'] 10 | tasks: 11 | - debug: 12 | var: results 13 | -------------------------------------------------------------------------------- /run_shell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: true 5 | tasks: 6 | - name: Run the specified shell command 7 | shell: '{{shell}}' 8 | register: result 9 | 10 | - name: Display the outcome 11 | debug: 12 | msg: '{{ result }}' 13 | -------------------------------------------------------------------------------- /inventories/script_migrations/large_5000.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | 4 | 5 | data = {"_meta": {"hostvars": {}}} 6 | 7 | for i in range(5000): 8 | data.setdefault("ungrouped", []).append("Host-{}".format(i)) 9 | 10 | print(json.dumps(data, indent=2)) 11 | -------------------------------------------------------------------------------- /sleep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: 'Test playbook to sleep for a specified interval' 4 | hosts: all 5 | gather_facts: false 6 | vars: 7 | sleep_interval: 30 8 | 9 | tasks: 10 | - name: sleep for a specified interval 11 | command: sleep '{{ sleep_interval }}' 12 | -------------------------------------------------------------------------------- /cloud_modules/rhv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test use of credentials with cloud module, taken from Ansible docs 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | 9 | - name: Ovirt (credential_type=rhv) 10 | tags: 11 | - rhv 12 | ovirt_auth: 13 | -------------------------------------------------------------------------------- /inventories/script_migrations/credential_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function 4 | import os, sys 5 | 6 | # Reads from a file that is laid down by a custom AWX credential 7 | 8 | print(open(os.environ["AWX_CUSTOM_INI"]).read(), file=sys.stderr) 9 | print("{}") 10 | -------------------------------------------------------------------------------- /gce_credentials_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Tests whether two environment variables are present (and non-empty) 4 | 5 | - hosts: local 6 | connection: local 7 | tasks: 8 | - shell: 'test -n "${GCE_EMAIL}"' 9 | - shell: 'test -n "${GCE_PROJECT}"' 10 | - shell: 'test -n "${GCE_PEM_FILE_PATH}"' 11 | -------------------------------------------------------------------------------- /test_collections/test_tower_organization.j2: -------------------------------------------------------------------------------- 1 | - name: Create an organization 2 | {{ collection_id }}.tower_organization: 3 | name: {{ organization_name | default("Test Org name") }} 4 | default_environment: {{ default_environment }} 5 | description: {{ description | default("default description") }} 6 | register: org 7 | -------------------------------------------------------------------------------- /cidr_merge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | tasks: 5 | 6 | - name: cidr_merge with merge action 7 | ansible.builtin.set_fact: 8 | value: 9 | - 192.168.0.0/17 10 | - 192.168.128.0/17 11 | - 192.168.128.1 12 | - debug: 13 | msg: '{{ value|ansible.utils.cidr_merge }}' 14 | -------------------------------------------------------------------------------- /inventories/script_migrations/ordering.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | 5 | 6 | print( 7 | json.dumps( 8 | { 9 | "_meta": {"hostvars": {"h01": {}, "h02": {}, "h03": {}}}, 10 | "agroup": {"hosts": ["h01", "h02", "h03"]}, 11 | } 12 | ) 13 | ) 14 | -------------------------------------------------------------------------------- /cat_files.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - command: 'cat {{ file_to_cat1|default(ansible_env.AP_FILE_TO_CAT1) }}' 5 | register: cat1 6 | - command: 'cat {{ file_to_cat2|default(ansible_env.AP_FILE_TO_CAT2) }}' 7 | register: cat2 8 | - debug: 9 | var: cat1 10 | - debug: 11 | var: cat2 12 | -------------------------------------------------------------------------------- /debug-loop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | vars: 5 | sleep_interval: 1 6 | num_messages: 50 7 | tasks: 8 | - name: debug and sleep for configured time 9 | include_tasks: debug_and_sleep.yml 10 | vars: 11 | message_number: "{{ item }}" 12 | loop: "{{ range(0, num_messages|int)|list }}" 13 | -------------------------------------------------------------------------------- /rescued_not_failed.yml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | gather_facts: false 3 | connection: local 4 | tasks: 5 | - name: Fail and rescue - collection of tasks 6 | block: 7 | - fail: 8 | msg: "HALP!!! time number {{ item }}" 9 | loop: 10 | - 1 11 | - 2 12 | rescue: 13 | - debug: msg="ε-(´・`) フ" 14 | -------------------------------------------------------------------------------- /test_collections/test_tower_workflow_approval.j2: -------------------------------------------------------------------------------- 1 | - name: Use the workflow_approval 2 | {{ collection_id }}.tower_workflow_approval: 3 | name: {{ name }} 4 | workflow_job_id: {{ workflow_job_id }} 5 | action: {{ action }} 6 | timeout: {{ timeout | default("") }} 7 | interval: {{ interval | default("") }} 8 | register: workflow_approval 9 | -------------------------------------------------------------------------------- /chatty_payload.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | vars: 5 | message_size: 1024 #message size in Bytes[1KB] 6 | num_messages: 10 #number of messages 7 | chatty_message: "{{ '$' * message_size|int }}" 8 | tasks: 9 | - debug: 10 | msg: "{{ chatty_message }}" 11 | with_sequence: "count={{ num_messages }}" 12 | -------------------------------------------------------------------------------- /test_tags_include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The purpose of this playbook is to be included by test_tags.yml 3 | - name: test_include_tags 4 | hosts: localhost 5 | gather_facts: False 6 | connection: local 7 | tasks: 8 | - name: included_task 9 | debug: msg= 10 | - name: included_task_with_tag 11 | debug: msg= 12 | tags: tag_included_task 13 | -------------------------------------------------------------------------------- /debug_dynamic_variable.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | connection: local 4 | gather_facts: false 5 | vars: 6 | default_var: foobar 7 | var_name: default_var 8 | leading_text: "specified_var_is:" 9 | tasks: 10 | - name: Print value of variable specified by var_name contents 11 | debug: msg="{{ leading_text }}{{ lookup('vars', var_name) }}" 12 | -------------------------------------------------------------------------------- /debug_extra_vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - debug: var=var1 7 | when: var1 is defined 8 | 9 | - debug: msg='var1 not defined' 10 | when: var1 is not defined 11 | 12 | - debug: var=var2 13 | when: var1 is defined 14 | 15 | - debug: msg='var2 not defined' 16 | when: var2 is not defined 17 | -------------------------------------------------------------------------------- /custom_json.yml: -------------------------------------------------------------------------------- 1 | - name: test playbooks that utilize ansible-specific json data types 2 | hosts: localhost 3 | connection: local 4 | gather_facts: False 5 | tasks: 6 | - name: include extra vars with vault/unsafe tags 7 | include_vars: custom_json_vars.yml 8 | - debug: msg="{{ vaulted_text }}" 9 | - debug: msg="{{ unsafe_text }}" 10 | - debug: msg="{{ datetime_text }}" 11 | -------------------------------------------------------------------------------- /patch_and_reboot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # playbook that exercies a serial patch and reboot of all the specified hosts 3 | - name: patch and reboot 4 | hosts: all 5 | gather_facts: no 6 | serial: 1 7 | become: true 8 | tasks: 9 | - name: upgrade packages 10 | ansible.builtin.dnf: 11 | name: "*" 12 | state: latest 13 | 14 | - name: reboot host 15 | ansible.builtin.reboot: 16 | -------------------------------------------------------------------------------- /gather_facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | vars: 5 | play_gather: true 6 | extra_value: "" 7 | gather_facts: "{{ play_gather }}" 8 | tasks: 9 | - name: set a fact man 10 | set_fact: 11 | foo: "bar{{ extra_value }}" 12 | bar: 13 | a: 14 | b: 15 | - "c" 16 | - "d" 17 | cacheable: "{{ set_fact_cacheable | default(false) }}" 18 | -------------------------------------------------------------------------------- /inventories/script_migrations/ansible_host.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import os 5 | 6 | ansible_host = os.environ.get("SCRIPT_HOST", "localhost") 7 | 8 | inventory = dict() 9 | inventory["some_group"] = dict() 10 | inventory["some_group"]["hosts"] = [ansible_host] 11 | inventory["some_group"]["vars"] = dict(ansible_connection="local") 12 | 13 | print(json.dumps(inventory)) 14 | -------------------------------------------------------------------------------- /inventories/script_migrations/large_dense.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import os 4 | 5 | 6 | Ng = int(os.environ.get("NUM_GROUPS", 470)) 7 | Nh = int(os.environ.get("NUM_HOSTS", 189)) 8 | 9 | 10 | data = {"_meta": {"hostvars": {}}} 11 | 12 | hosts = ["Host-{}".format(i) for i in range(Nh)] 13 | 14 | for i in range(Ng): 15 | data["Group-{}".format(i)] = {"hosts": hosts} 16 | 17 | print(json.dumps(data, indent=2)) 18 | -------------------------------------------------------------------------------- /test_collections/test_tower_execution_environment.j2: -------------------------------------------------------------------------------- 1 | - name: Create an tower_execution_environment 2 | {{ collection_id }}.tower_execution_environment: 3 | name: {{ name }} 4 | image: {{ image | default("quay.io/ansible/awx-ee:devel") }} 5 | description: {{ description | default("default description") }} 6 | organization: {{ organization | default("")}} 7 | pull: {{ pull | default("missing")}} 8 | register: execution_environment 9 | -------------------------------------------------------------------------------- /test_collections/test_tower_inventory_source.j2: -------------------------------------------------------------------------------- 1 | - name: Create an tower_inventory_source 2 | {{ collection_id }}.tower_inventory_source: 3 | name: {{ name }} 4 | inventory: {{ inventory }} 5 | description: {{ description }} 6 | source: {{ source }} 7 | source_project: {{ source_project }} 8 | source_path: {{ source_path }} 9 | execution_environment: {{ execution_environment }} 10 | register: inventory_source 11 | -------------------------------------------------------------------------------- /scan_custom.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | gather_facts: false 3 | tasks: 4 | - test_scan_facts: 5 | - debug: 6 | msg: "{{item}}" 7 | with_items: 8 | - "{{string}}" 9 | - "{{unicode_string}}" 10 | - "{{int}}" 11 | - "{{float}}" 12 | - "{{bool}}" 13 | - "{{null}}" 14 | - "{{list}}" 15 | - "{{obj}}" 16 | - "{{empty_list}}" 17 | - "{{empty_obj}}" 18 | -------------------------------------------------------------------------------- /cloud_modules/k8s.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | collections: 6 | - community.kubernetes 7 | tasks: 8 | - name: Get a list of all pods from any namespace 9 | k8s_info: 10 | kind: Pod 11 | namespace: "{{ namespace }}" 12 | register: pod_list 13 | 14 | - name: Print pod names 15 | debug: 16 | msg: "{{ item.metadata.name }} " 17 | with_items: "{{ pod_list.resources }}" 18 | -------------------------------------------------------------------------------- /cloud_modules/openstack.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test use of credentials with cloud module, taken from Ansible docs 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | 9 | - name: Create a new instance, per example (credential_type=openstack) 10 | tags: 11 | - openstack 12 | os_server: 13 | state: "{{ state | default('absent') }}" 14 | name: 8ut0o26a1g # should not match anything 15 | 16 | -------------------------------------------------------------------------------- /inventories/script_migrations/empty_group.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | 5 | print( 6 | json.dumps( 7 | { 8 | "_meta": {"hostvars": {"old_host": {}}}, 9 | "ungrouped": {"hosts": ["old_host"]}, 10 | "ghost": {"hosts": [], "vars": {"foobar": "hello_world"}}, 11 | "ghost2": {"hosts": []}, 12 | "all": {"children": ["ghost3"]}, 13 | } 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /read_file_content.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: 'Test playbook to read the content from a file' 4 | hosts: all 5 | gather_facts: false 6 | 7 | tasks: 8 | 9 | - name: "Get {{ filepath }} content" 10 | command: "cat {{ filepath }}" 11 | register: cnt 12 | 13 | - name: "Check if {{ filepath }} content is correct" 14 | fail: 15 | msg: "{{ filepath }} doesnt have the correct content" 16 | when: '"{{ cnt_to_check }}" not in cnt.stdout' -------------------------------------------------------------------------------- /test_collections/test_tower_project.j2: -------------------------------------------------------------------------------- 1 | - name: Create a project 2 | {{ collection_id }}.tower_project: 3 | name: {{ project_name | default("Default project name") }} 4 | default_environment: {{ default_environment }} 5 | description: {{ description | default("default description") }} 6 | scm_type: {{ scm_type }} 7 | scm_url: {{ scm_url }} 8 | organization: {{ organization }} 9 | default_environment: {{ default_environment }} 10 | register: project 11 | -------------------------------------------------------------------------------- /utils/multivault-dotted-vars.yml: -------------------------------------------------------------------------------- 1 | dotted: !vault | 2 | $ANSIBLE_VAULT;1.1;AES256;dotted.id 3 | 32363764366261386339653030393130623731306264353133333163393331613337383936373331 4 | 3938366439366135353038626665663434343738363831370a303463623433376165633831616666 5 | 31333332346336346533656462353634646265626363333637623931313837363437346461666635 6 | 3964316165373561390a323632633764646166363130623934346364363533366635313332623236 7 | 6432 8 | -------------------------------------------------------------------------------- /inventories/script_migrations/large_sparse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import os 4 | 5 | 6 | Ng = int(os.environ.get("NUM_GROUPS", 25)) 7 | Nh = int(os.environ.get("NUM_HOSTS", 25)) 8 | 9 | 10 | data = {"_meta": {"hostvars": {}}} 11 | 12 | for i in range(Nh): 13 | data.setdefault("ungrouped", []).append("Host-{}".format(i)) 14 | 15 | for i in range(Ng): 16 | data["Group-{}".format(i)] = {"vars": {"foo": "bar"}} 17 | 18 | print(json.dumps(data, indent=2)) 19 | -------------------------------------------------------------------------------- /inventories/dyn_inventory_sleep_60s.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from datetime import datetime 4 | import json 5 | 6 | import time 7 | 8 | inventory = { 9 | 'all': {'vars': {'ansible_connection': 'local'}}, 10 | 'ungrouped': {'hosts': ['localhost']}, 11 | '_meta': {'hostvars': {'localhost': { 12 | 'current_time': str(datetime.now()) 13 | }}} 14 | } 15 | 16 | 17 | if __name__ == '__main__': 18 | time.sleep(60) 19 | print(json.dumps(inventory, indent=4)) 20 | -------------------------------------------------------------------------------- /cloud_modules/tower.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test use of credentials with cloud module, taken from Ansible docs 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | 9 | - name: Create an Inventory in Tower (credential_type=tower) 10 | tags: 11 | - tower 12 | tower_inventory: 13 | name: my_inventory_8ut0o26a1g # should not match anything 14 | organization: Default 15 | state: "{{ state | default('absent') }}" 16 | 17 | -------------------------------------------------------------------------------- /inventories/script_migrations/bad_script_4.py: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cat << EOF 3 | { 4 | "all": {"hosts": ["{{ lookup('pipe', 'touch /tmp/foobar') }}", "localhost"]}, 5 | "_meta": { 6 | "hostvars": { 7 | "{{ lookup('pipe', 'touch /tmp/foobar') }}": {}, 8 | "localhost": { 9 | "ansible_connection": "local", 10 | "ansible_python_interpreter": "{{ ansible_playbook_python }}", 11 | }, 12 | } 13 | }, 14 | } 15 | EOF 16 | -------------------------------------------------------------------------------- /test_ansible_shell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify that ansible can correctly pass arguments to ansible in shell 3 | hosts: all 4 | gather_facts: False 5 | tasks: 6 | - name: Write inventory file 7 | blockinfile: 8 | path: '/tmp/inventory.ansible.shell' 9 | block: | 10 | localhost ansible_connection=local 11 | state: present 12 | create: True 13 | 14 | - name: Run Playbook 15 | shell: "ANSIBLE_NOCOLOR=1 ansible-playbook -i '/tmp/inventory.ansible.shell' ./ping.yml" 16 | -------------------------------------------------------------------------------- /test_collections/test_tower_job.j2: -------------------------------------------------------------------------------- 1 | - name: launch Job 2 | {{ collection_id }}.tower_job_launch: 3 | job_template: {{ job_template }} 4 | register: launch_job 5 | 6 | - name: cancel Job 7 | {{ collection_id }}.tower_job_cancel: 8 | job_id: {{ job_id }} 9 | register: cancel_job 10 | 11 | - name: wait Job 12 | {{ collection_id }}.tower_job_wait: 13 | job_id: {{ job_template }} 14 | register: wait_job 15 | 16 | - name: list Job 17 | {{ collection_id }}.tower_job_list: 18 | job_id: {{ job_template }} 19 | register: list_job 20 | -------------------------------------------------------------------------------- /cloud_modules/aws.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test use of credentials with cloud module, taken from Ansible docs 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | 9 | - name: Add or remove this specific tag from instance (credential_type=aws) 10 | ec2_tag: 11 | region: us-east-2 12 | resource: "{{ instance_id | default('i-8a6ff363') }}" 13 | tags: 14 | Foooooo: '' 15 | state: "{{ state | default('absent') }}" 16 | purge_tags: false 17 | tags: 18 | - aws 19 | -------------------------------------------------------------------------------- /cloud_modules/vmware.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test use of credentials with cloud module, taken from Ansible docs 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | 9 | - name: VMWare Clone the template (credential_type=vmware) 10 | tags: 11 | - vmware 12 | vmware_guest: 13 | name: testvm_2_8ut0o26a1g # should not match anything 14 | template: template_el7 15 | datacenter: DC1 16 | folder: /DC1/vm 17 | state: "{{ state | default('absent') }}" 18 | wait_for_ip_address: yes 19 | -------------------------------------------------------------------------------- /inventories/script_migrations/large_hostvars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import random 4 | import string 5 | 6 | 7 | UNICODE_LETTERS = string.ascii_letters + ("읤僪䠱빨胀콩厺殜赬镗צּ䂕ᆑ䭆蜅펵ꂢ綌靸縹聂傈㟩륯Ȳ北벊렙ぶ逖ϥ谺艣뒉摳") 8 | 9 | 10 | random_str = "".join([random.choice(UNICODE_LETTERS) for _ in range(10)]) 11 | 12 | inv = { 13 | "somegroup{0}".format(random_str): dict( 14 | hosts=["somehost{0}".format(random_str)], 15 | vars=dict( 16 | ansible_host="127.0.0.1", ansible_connection="local", cruft="x" * 1024 ** 2 17 | ), 18 | ) 19 | } 20 | 21 | print(json.dumps(inv)) 22 | -------------------------------------------------------------------------------- /test_collections/test_tower_job_template.j2: -------------------------------------------------------------------------------- 1 | - name: Create a job template 2 | {{ collection_id }}.tower_job_template: 3 | name: {{ job_template_name | default("Default jt name") }} 4 | execution_environment: {{ execution_environment }} 5 | description: {{ description | default("default description") }} 6 | job_type: {{ job_type }} 7 | inventory: {{ inventory }} 8 | playbook: {{ playbook }} 9 | project: {{ project }} 10 | vault_credential: {{ vault_credential }} 11 | extra_vars: {{ extra_vars }} 12 | state: {{ state | default("present") }} 13 | register: job_template 14 | -------------------------------------------------------------------------------- /utils/trigger_update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat << EOF > ~/git_ssh 4 | #/usr/bin/env bash 5 | exec /usr/bin/ssh -o StrictHostKeyChecking=no -i $GIT_KEY "\$@" 6 | EOF 7 | 8 | chmod a+x ~/git_ssh 9 | export GIT_SSH=~/git_ssh 10 | 11 | TMPFILE='random'$RANDOM 12 | git checkout inventory_additions 13 | touch $TMPFILE 14 | git add $TMPFILE 15 | git commit -m "Adding temporary file $TMPFILE" 16 | git push -f git@github.com:ansible/test-playbooks.git inventory_additions 17 | git rm $TMPFILE 18 | git commit -m "Removing temporary file $TMPFILE" 19 | git push -f git@github.com:ansible/test-playbooks.git inventory_additions 20 | -------------------------------------------------------------------------------- /serial.yml: -------------------------------------------------------------------------------- 1 | - name: First Play. Using serial strategy. 2 | hosts: all 3 | gather_facts: yes 4 | serial: 1 5 | tasks: 6 | - name: Play1 Debug1 task 7 | debug: 8 | msg: "This is Play1 debug1 task" 9 | 10 | - name: Play1 Debug2 task 11 | debug: 12 | msg: "This is Play1 debug2 task" 13 | 14 | - name: Second Play. Using default strategy. 15 | hosts: all 16 | gather_facts: yes 17 | tasks: 18 | - name: Play2 Debug1 task 19 | debug: 20 | msg: "This is Play2 debug1 task" 21 | 22 | - name: Play2 Debug2 task 23 | debug: 24 | msg: "This is Play2 debug2 task" 25 | -------------------------------------------------------------------------------- /bursting_events.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | connection: local 6 | vars: 7 | num_messages: 50 8 | tasks: 9 | - debug: 10 | msg: "This is a debug message: {{ item }}" 11 | with_sequence: 'count={{ num_messages }}' 12 | 13 | - debug: 14 | msg: last message before a pause 15 | run_once: true 16 | 17 | - pause: 18 | seconds: 5 19 | 20 | - debug: 21 | msg: "This is a debug message: {{ item }}" 22 | with_sequence: 'count={{ num_messages }}' 23 | 24 | - debug: 25 | msg: last message before then end 26 | run_once: true 27 | -------------------------------------------------------------------------------- /vaulted_ansible_env.yml: -------------------------------------------------------------------------------- 1 | $ANSIBLE_VAULT;1.1;AES256 2 | 30383632343130323134646263636562366265313762376231623536316566616437373764383138 3 | 3835313535613535316236383935376566366565316531630a316463346665393861323662366163 4 | 61373566333833663432373634376532333961396138353764666665336162633035393965373539 5 | 6536323932323032320a306266626533656662306663623363633366366432356232313332306461 6 | 37633364343264353762623232623633393137643262616664623764346239613435653631366334 7 | 30386565363064623764353831613363386431313537393261343039386434363763396239343538 8 | 64393363366365343561643365366533613433656333346334646135326434303861363530323538 9 | 61373963663035323563 10 | -------------------------------------------------------------------------------- /environ_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Tests whether the provided environment variable exists and matches the provided value 3 | 4 | - hosts: all 5 | 6 | tasks: 7 | - name: 'assert expected variables are defined' 8 | assert: 9 | that: 10 | - env_variable is defined 11 | - env_value is defined 12 | 13 | - name: 'assert that the desired environment variable is defined' 14 | assert: 15 | that: 16 | - "lookup('env','{{env_variable}}')" 17 | 18 | - name: 'assert that the desired environment matches the expected value' 19 | assert: 20 | that: 21 | - "lookup('env','{{env_variable}}') == '{{env_value}}'" 22 | -------------------------------------------------------------------------------- /inventories/user_plugins/README.md: -------------------------------------------------------------------------------- 1 | ### Custom Inventory Plugins 2 | 3 | This contains examples of using source control to maintain and vendor 4 | custom inventory plugins. 5 | 6 | Ansible users should place their inventory 7 | plugins inside an `inventory_plugins` folder within the same folder 8 | as their inventory to have it read by AWX in an inventory import. 9 | 10 | cd into this directory in order to test manually with these commands: 11 | 12 | This should work: 13 | 14 | ``` 15 | ansible-inventory -i cow.yaml --list --export --playbook-dir=. 16 | ``` 17 | 18 | This should raise an exception: 19 | 20 | ``` 21 | ansible-inventory -i fox.yaml --list --export --playbook-dir=. 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /custom_json_vars.yml: -------------------------------------------------------------------------------- 1 | vaulted_text: !vault | 2 | $ANSIBLE_VAULT;1.2;AES256;alan 3 | 36386366323637343336383236333964643463626232663931323932616365616263646434356166 4 | 6533313834316664626239396336326333643163353433340a623537336431313534393531663464 5 | 65316639396361316664373732366438636638336439636166643832626432646231313633396666 6 | 6435326436663766370a663466633064376161336439303166353139326335313665363030363437 7 | 66643364343863366365343964343764316231373638633633303265363763613836313435313266 8 | 31326665373432376461623162353038643935346633643862646632346532396263356135376431 9 | 613262626339313336643338653330613164 10 | unsafe_text: !unsafe "{{ unsafe }}" 11 | datetime_text: 2017-03-07T10:20:49Z 12 | -------------------------------------------------------------------------------- /vault.yml: -------------------------------------------------------------------------------- 1 | $ANSIBLE_VAULT;1.1;AES256 2 | 30666235383963666339363533616635623965616438613233363865623263336536383231623035 3 | 6234303962373165393239376635313163666336386563370a396361663164343130623335646538 4 | 30646364643536663838373262353562633065323738663731366531316365653361373130313938 5 | 3864613639633131380a666131616566326133336430333332623734646166643734653232373366 6 | 63386633373335383938323035363461666132353466623466616431363932633631363930626639 7 | 37623562383131373162653463333161626663623166613463383666323739336566326336366233 8 | 36366132643561373536313865336639303431393735353434366637633838646666623036373630 9 | 39353036653330393839353431636163343062303163333936306430656537633066323036383432 10 | 3731 11 | -------------------------------------------------------------------------------- /vaulted_debug_hostvars.yml: -------------------------------------------------------------------------------- 1 | $ANSIBLE_VAULT;1.1;AES256 2 | 37623334633461633530383834643462386636306463356134363564616161386261396662633239 3 | 3262366430346632626238353038373330613661353434380a633135386230383561313536623837 4 | 33623031373235313766326234663764633937356633643962643261343235356332633138353538 5 | 3365303636636438640a653634333130663362616431656235333739343463336134623739613033 6 | 63326232366435616661363464373838353563666163373265623365386439633363636331343637 7 | 35643362313030393761323066613730383130383366636635356166333062643362653364343963 8 | 31376338633639636433666463306666343663386339633935383163326337386534353436373064 9 | 39346263303462346364356136356238363137353966303564313666356231333739383331396436 10 | 3734 11 | -------------------------------------------------------------------------------- /file_finder.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Find file and send it's content as an artifact 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | tasks: 7 | - name: Find all files 8 | find: 9 | file_type: file 10 | hidden: True 11 | recurse: True 12 | paths: .. 13 | register: files 14 | 15 | - name: Extract file content 16 | set_fact: 17 | file_content: "{{ file_content | default({}) | combine({ item.path: lookup('file', item.path) }) }}" 18 | when: | 19 | "../project" not in item.path 20 | loop: "{{ files.files }}" 21 | loop_control: 22 | label: "{{ item.path }}" 23 | 24 | - name: Set job stats 25 | set_stats: 26 | data: 27 | files: "{{ file_content }}" 28 | -------------------------------------------------------------------------------- /inventories/script_migrations/test_limit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | 4 | # Create hosts and groups 5 | inv = dict(_meta=dict(hostvars={}), hosts=[]) 6 | inv["group-0"] = [ 7 | "duplicate_host", 8 | "host with spaces in name", 9 | "host-1", 10 | "host-2", 11 | "host-3", 12 | ] 13 | inv["group-1"] = [ 14 | "duplicate_host", 15 | "host-4", 16 | "host-5", 17 | "host-6", 18 | ] 19 | inv["group-2"] = [ 20 | "duplicate_host", 21 | "host-7", 22 | "host-8", 23 | "host-9", 24 | ] 25 | 26 | # Add _meta hostvars 27 | for grp, hosts in inv.items(): 28 | for host in hosts: 29 | inv["_meta"]["hostvars"][host] = dict( 30 | ansible_host="127.0.0.1", ansible_connection="local" 31 | ) 32 | 33 | print(json.dumps(inv, indent=2)) 34 | -------------------------------------------------------------------------------- /inventories/invalid_dyn_inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | import json 4 | 5 | inventory = {'invalid': True} 6 | 7 | def parse_args(): 8 | parser = ArgumentParser() 9 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 10 | help='List instances (default: True)') 11 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 12 | return parser.parse_args() 13 | 14 | def dumps(dct): 15 | return json.dumps(dct, sort_keys=True, indent=4, separators=(',', ': ')) 16 | 17 | def load_inventory(): 18 | args = parse_args() 19 | if args.list_instances: 20 | print(dumps(inventory)) 21 | 22 | 23 | if __name__ == '__main__': 24 | load_inventory() 25 | -------------------------------------------------------------------------------- /test_set_stats.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | vars: 4 | set_stats_data: 5 | string: 'abc' 6 | integer: 123 7 | float: 1.0 8 | unicode: '竳䙭韽' 9 | boolean: true 10 | none: null 11 | list: 12 | - 'abc' 13 | - 123 14 | - 1.0 15 | - '竳䙭韽' 16 | - true 17 | - null 18 | - [] 19 | - {} 20 | object: 21 | string: 'abc' 22 | integer: 123 23 | float: 1.0 24 | unicode: '竳䙭韽' 25 | boolean: true 26 | none: null 27 | list: [] 28 | object: {} 29 | empty_list: [] 30 | empty_object: {} 31 | fail_at_end: false 32 | tasks: 33 | - set_stats: 34 | data: "{{ set_stats_data }}" 35 | - fail: "Intentionally failing because variable 'fail_at_end' was set to {{ fail_at_end }}" 36 | when: fail_at_end 37 | -------------------------------------------------------------------------------- /inventories/user_plugins/inventory_plugins/cow.py: -------------------------------------------------------------------------------- 1 | from __future__ import (absolute_import, division, print_function) 2 | __metaclass__ = type 3 | 4 | DOCUMENTATION = r''' 5 | inventory: cow 6 | version_added: "2.7" 7 | short_description: Returns string "moooooo" for values of stuff 8 | description: 9 | - Ignores whatever you give it 10 | - Returns inventory containing "moooooo" 11 | ''' 12 | 13 | EXAMPLES = r''' 14 | # mooooo 15 | ''' 16 | 17 | from ansible.plugins.inventory import BaseInventoryPlugin 18 | 19 | 20 | class InventoryModule(BaseInventoryPlugin): 21 | 22 | NAME = 'cow' 23 | 24 | def parse(self, inventory, loader, host_list, cache=True): 25 | ''' doesnt parse the inventory file, but claims it did anyway ''' 26 | super(InventoryModule, self).parse(inventory, loader, host_list) 27 | self.inventory.add_host('moooooo') 28 | -------------------------------------------------------------------------------- /ping-20.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - name: ping-01 7 | ping: 8 | - name: ping-02 9 | ping: 10 | - name: ping-03 11 | ping: 12 | - name: ping-04 13 | ping: 14 | - name: ping-05 15 | ping: 16 | - name: ping-06 17 | ping: 18 | - name: ping-07 19 | ping: 20 | - name: ping-08 21 | ping: 22 | - name: ping-09 23 | ping: 24 | - name: ping-10 25 | ping: 26 | - name: ping-11 27 | ping: 28 | - name: ping-12 29 | ping: 30 | - name: ping-13 31 | ping: 32 | - name: ping-14 33 | ping: 34 | - name: ping-15 35 | ping: 36 | - name: ping-16 37 | ping: 38 | - name: ping-17 39 | ping: 40 | - name: ping-18 41 | ping: 42 | - name: ping-19 43 | ping: 44 | - name: ping-20 45 | ping: 46 | -------------------------------------------------------------------------------- /inventories/script_migrations/script_source.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | import random 6 | import string 7 | 8 | 9 | random.seed(29973595994172) 10 | 11 | 12 | def random_str(non_ascii=True): 13 | char_list = string.ascii_letters 14 | if non_ascii: 15 | char_list += (u"읤僪䠱빨胀콩厺殜赬镗צּ䂕ᆑ䭆蜅펵ꂢ綌靸縹聂傈㟩륯Ȳ北벊렙ぶ逖ϥ谺艣뒉摳") 16 | return "".join([random.choice(char_list) for _ in range(10)]) 17 | 18 | 19 | inventory = dict() 20 | 21 | group_name = "group_%s" % random_str(non_ascii=False) 22 | 23 | inventory[group_name] = dict() 24 | inventory[group_name]["hosts"] = list() 25 | 26 | for i in range(5): 27 | inventory[group_name]["hosts"].append("host_%s" % random_str()) 28 | 29 | inventory[group_name]["vars"] = dict( 30 | ansible_host="127.0.0.1", ansible_connection="local" 31 | ) 32 | 33 | print(json.dumps(inventory, ensure_ascii=False)) 34 | -------------------------------------------------------------------------------- /inventories/more_inventories/inventory.ini: -------------------------------------------------------------------------------- 1 | ungrouped_host_[06:10] 2 | group_four_host_01 group_four_host_01_has_this_var=True 3 | group_five_host_01 group_five_host_01_has_this_var=True 4 | group_six_host_01 group_six_host_01_has_this_var=True 5 | 6 | [group_four] 7 | group_four_host_[01:05] 8 | group_four_and_five_host_[01:05] 9 | group_four_five_and_six_host_[01:05] 10 | 11 | [group_four:vars] 12 | is_in_group_four=True 13 | 14 | [group_five] 15 | group_five_host_[01:05] 16 | group_four_and_five_host_[01:05] 17 | group_five_and_six_host_[01:05] 18 | group_four_five_and_six_host_[01:05] 19 | 20 | [group_five:vars] 21 | is_in_group_five=True 22 | 23 | [group_six] 24 | group_six_host_[01:05] 25 | group_five_and_six_host_[01:05] 26 | group_four_five_and_six_host_[01:05] 27 | 28 | [group_six:vars] 29 | is_in_group_six=True 30 | 31 | [all:vars] 32 | ansible_connection=local 33 | more_inventories_var=True 34 | -------------------------------------------------------------------------------- /inventories/linode.yml: -------------------------------------------------------------------------------- 1 | plugin: linode 2 | # Linode inventory plugin inventory, partial example 3 | # 4 | # This should be operable with only the access_token provided 5 | # the linode inventory plugin also allows for providing the 6 | # access token via an environment variable, so you might use this like: 7 | # 8 | # LINODE_ACCESS_TOKEN=foobar ansible-inventory -i plugins/example_linode/linode.yml --list 9 | # 10 | # The linode inventory plugin was (or will be) introduced in Ansible 2.8 11 | # If you do not have that version of Ansible, it should give an error 12 | # from the auto plugin that the inventory specifies unknown plugin 13 | # This requires linode_api4 dependency to work, so in your venv run: 14 | # pip install linode_api4 15 | # without that, it will error that it requires linode_api4 16 | # If you don't specify the auth token, then it should give an error specific 17 | # to this scenario, that auth isn't specified 18 | -------------------------------------------------------------------------------- /inventories/script_migrations/delete_group_3_custom_script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import uuid 5 | 6 | unique_name = str(uuid.uuid4()) 7 | host_1 = "host_{}".format(unique_name) 8 | host_2 = "host_2_{}".format(unique_name) 9 | print( 10 | json.dumps( 11 | { 12 | "_meta": { 13 | "hostvars": { 14 | "{}".format(host_1): {"name": "{}".format(host_1)}, 15 | "{}".format(host_2): {"name": "{}".format(host_2)}, 16 | "all_have": {"name": "all_have"}, 17 | "all_have2": {"name": "all_have2"}, 18 | "all_have3": {"name": "all_have3"}, 19 | } 20 | }, 21 | "child_group": {"hosts": ["{}".format(host_1), "all_have"]}, 22 | "child_group2": {"hosts": ["{}".format(host_1), "all_have2"]}, 23 | } 24 | ) 25 | ) 26 | -------------------------------------------------------------------------------- /test_tags.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: test_task_tags 3 | hosts: localhost 4 | gather_facts: False 5 | connection: local 6 | tasks: 7 | - name: task_with_tag 8 | debug: msg= 9 | tags: tag 10 | - name: task_with_multiple_tags 11 | debug: msg= 12 | tags: [tag, other_tag] 13 | - name: task_with_always_tag 14 | debug: msg= 15 | tags: always 16 | - name: task_without_tag 17 | debug: msg= 18 | 19 | - name: test_inherited_tags 20 | hosts: localhost 21 | gather_facts: False 22 | connection: local 23 | tags: 24 | - inherited_tag 25 | tasks: 26 | - name: task_with_inherited_tag 27 | debug: msg= 28 | 29 | - name: test_role_tags 30 | hosts: localhost 31 | gather_facts: False 32 | connection: local 33 | roles: 34 | - { role: test_tag_role, test_tag_role_msg: 'role_with_tag', tags: [ 'tag_role' ] } 35 | 36 | - include: test_tags_include.yml 37 | tags: tag_include 38 | -------------------------------------------------------------------------------- /write_file_content.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: 'Test playbook to write content into a file' 4 | hosts: all 5 | gather_facts: false 6 | vars: 7 | content: 'Test_Content_Line' 8 | tasks: 9 | 10 | - name: "Write content into a file" 11 | copy: 12 | dest: "{{ filepath }}" 13 | content: "{{ content }}" 14 | 15 | - name: "Check file {{ filepath }} stat result" 16 | stat: 17 | path: "{{ filepath }}" 18 | register: st 19 | 20 | - name: "Check if file {{ filepath }} exists" 21 | fail: 22 | msg: "{{ filepath }} doesnt exist" 23 | when: not st.stat.exists | bool 24 | 25 | - name: "Get {{ filepath }} content" 26 | command: "cat {{ filepath }}" 27 | register: cnt 28 | 29 | - name: "Check if {{ filepath }} content is correct" 30 | fail: 31 | msg: "{{ filepath }} doesnt have the correct content" 32 | when: '"{{ content }}" not in cnt.stdout' -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/inventory.ini: -------------------------------------------------------------------------------- 1 | ungrouped_host_[11:15] 2 | group_seven_host_01 group_seven_host_01_has_this_var=True 3 | group_eight_host_01 group_eight_host_01_has_this_var=True 4 | group_nine_host_01 group_nine_host_01_has_this_var=True 5 | 6 | [group_seven] 7 | group_seven_host_[01:05] 8 | group_seven_and_eight_host_[01:05] 9 | group_seven_eight_and_nine_host_[01:05] 10 | 11 | [group_seven:vars] 12 | is_in_group_seven=True 13 | 14 | [group_eight] 15 | group_eight_host_[01:05] 16 | group_seven_and_eight_host_[01:05] 17 | group_eight_and_nine_host_[01:05] 18 | group_seven_eight_and_nine_host_[01:05] 19 | 20 | [group_eight:vars] 21 | is_in_group_eight=True 22 | 23 | [group_nine] 24 | group_nine_host_[01:05] 25 | group_eight_and_nine_host_[01:05] 26 | group_seven_eight_and_nine_host_[01:05] 27 | 28 | [group_nine:vars] 29 | is_in_group_nine=True 30 | 31 | [all:vars] 32 | ansible_connection=local 33 | even_more_inventories_var=True 34 | -------------------------------------------------------------------------------- /inventories/script_migrations/overwrite1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | 5 | print( 6 | json.dumps( 7 | { 8 | "_meta": {"hostvars": {"host_1": {}, "host_2": {}}}, 9 | "ungrouped": {"hosts": ["will_remove_host"]}, 10 | "child_group": {"hosts": ["host_of_child"]}, 11 | "child_group2": {"hosts": ["host_of_child"]}, 12 | "not_child": {"hosts": ["host_of_not_child"]}, 13 | "switch1": {"hosts": ["host_switch1"]}, 14 | "switch2": {"hosts": ["host_switch2"]}, 15 | "parent_switch1": {"children": ["switch1"]}, 16 | "parent_switch2": {"children": ["switch2"]}, 17 | "will_remove_group": {"hosts": ["host_2"]}, 18 | "parent_group": { 19 | "hosts": ["host_1", "host_2"], 20 | "children": ["child_group", "child_group2"], 21 | }, 22 | } 23 | ) 24 | ) 25 | -------------------------------------------------------------------------------- /inventories/inventory.ini: -------------------------------------------------------------------------------- 1 | ungrouped_host_[01:05] 2 | group_one_host_01 group_one_host_01_has_this_var=True 3 | group_two_host_01 group_two_host_01_has_this_var=True 4 | group_three_host_01 group_three_host_01_has_this_var=True 5 | 6 | [group_one] 7 | group_one_host_[01:05] 8 | group_one_and_two_host_[01:05] 9 | group_one_two_and_three_host_[01:05] 10 | 11 | [group_one:vars] 12 | is_in_group_one=True 13 | complex_var=[{"dir": "/opt/gwaf/logs", "sourcetype": "gwaf", "something_else": [1, 2, 3]}] 14 | 15 | [group_two] 16 | group_two_host_[01:05] 17 | group_one_and_two_host_[01:05] 18 | group_two_and_three_host_[01:05] 19 | group_one_two_and_three_host_[01:05] 20 | 21 | [group_two:vars] 22 | is_in_group_two=True 23 | 24 | [group_three] 25 | group_three_host_[01:05] 26 | group_two_and_three_host_[01:05] 27 | group_one_two_and_three_host_[01:05] 28 | 29 | [group_three:vars] 30 | is_in_group_three=True 31 | 32 | [all:vars] 33 | ansible_connection=local 34 | inventories_var=True 35 | -------------------------------------------------------------------------------- /inventories/script_migrations/basic_structure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | 5 | print( 6 | json.dumps( 7 | { 8 | "_meta": {"hostvars": {"host_1": {}, "host_2": {}}}, 9 | "ungrouped": {"hosts": ["will_remove_host"]}, 10 | "child_group": {"hosts": ["host_of_child"]}, 11 | "child_group2": {"hosts": ["host_of_child"]}, 12 | "not_child": {"hosts": ["host_of_not_child"]}, 13 | "switch1": {"hosts": ["host_switch1"]}, 14 | "switch2": {"hosts": ["host_switch2"]}, 15 | "parent_switch1": {"children": ["switch1"]}, 16 | "parent_switch2": {"children": ["switch2"]}, 17 | "will_remove_group": {"hosts": ["host_2"]}, 18 | "parent_group": { 19 | "hosts": ["host_1", "host_2"], 20 | "children": ["child_group", "child_group2"], 21 | }, 22 | } 23 | ) 24 | ) 25 | -------------------------------------------------------------------------------- /inventories/constructed/README.md: -------------------------------------------------------------------------------- 1 | ### Demo Problem for Smart Inventory hostvars Filtering 2 | 3 | This hosts the original demo problem for "constructed" inventory. 4 | Original location was at: 5 | 6 | https://github.com/AlanCoding/Ansible-inventory-file-examples/tree/master/issues/AWX371 7 | 8 | Original related issue is: 9 | 10 | https://github.com/ansible/awx/issues/371 11 | 12 | The key contents are the `east.ini` and `west.ini` inventories in this folder, 13 | which are intended to be combined by a constructed inventory with the 14 | following parameters: 15 | 16 | #### Constructed inventory input (source_vars) 17 | 18 | ```yaml 19 | plugin: constructed 20 | strict: true 21 | groups: 22 | shutdown: resolved_state == "shutdown" 23 | shutdown_in_product_dev: resolved_state == "shutdown" and account_alias == "product_dev" 24 | compose: 25 | resolved_state: state | default("running") 26 | ``` 27 | 28 | #### Limit value 29 | 30 | ``` 31 | shutdown_in_product_dev 32 | ``` 33 | -------------------------------------------------------------------------------- /inventories/script_migrations/delete_group_2_custom_script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import uuid 5 | 6 | unique_name = str(uuid.uuid4()) 7 | host_1 = "host_{}".format(unique_name) 8 | host_2 = "host_2_{}".format(unique_name) 9 | print( 10 | json.dumps( 11 | { 12 | "_meta": { 13 | "hostvars": { 14 | "{}".format(host_1): {"name": "{}".format(host_1)}, 15 | "{}".format(host_2): {"name": "{}".format(host_2)}, 16 | "all_have": {"name": "all_have"}, 17 | "all_have2": {"name": "all_have2"}, 18 | "all_have3": {"name": "all_have3"}, 19 | } 20 | }, 21 | "child_group": {"hosts": ["{}".format(host_1), "all_have"]}, 22 | "parent_group": { 23 | "hosts": ["{}".format(host_2), "all_have3"], 24 | "children": ["child_group"], 25 | }, 26 | } 27 | ) 28 | ) 29 | -------------------------------------------------------------------------------- /inventories/script_migrations/delete_group_1_custom_script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import uuid 5 | 6 | unique_name = str(uuid.uuid4()) 7 | host_1 = "host_{}".format(unique_name) 8 | host_2 = "host_2_{}".format(unique_name) 9 | print( 10 | json.dumps( 11 | { 12 | "_meta": { 13 | "hostvars": { 14 | "{}".format(host_1): {"name": "{}".format(host_1)}, 15 | "{}".format(host_2): {"name": "{}".format(host_2)}, 16 | "all_have": {"name": "all_have"}, 17 | "all_have2": {"name": "all_have2"}, 18 | "all_have3": {"name": "all_have3"}, 19 | } 20 | }, 21 | "child_group2": {"hosts": ["{}".format(host_1), "all_have2"]}, 22 | "parent_group": { 23 | "hosts": ["{}".format(host_2), "all_have3"], 24 | "children": ["child_group2"], 25 | }, 26 | } 27 | ) 28 | ) 29 | -------------------------------------------------------------------------------- /tower_collection_smoke.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: false 4 | vars: 5 | collection_id: awx.awx 6 | src_file: tower_collection_smoke.j2 7 | dest_file: tower_collection_actual.yml 8 | tasks: 9 | - name: "List what collections are installed (only available with ansible 2.10+)" 10 | shell: "ansible-galaxy collection list" 11 | register: ansible_collections_list 12 | when: ansible_version.full is version('2.10.0', '>=') 13 | 14 | - name: "Echo what collections are installed (only available with ansible 2.10+)" 15 | debug: 16 | msg: "{{ ansible_collections_list.stdout_lines }}" 17 | when: ansible_version.full is version('2.10.0', '>=') 18 | 19 | - name: "Create playbook to call with collection FQCN" 20 | template: 21 | src: "{{ src_file }}" 22 | dest: "{{ dest_file }}" 23 | 24 | - include: "{{ dest_file }}" 25 | 26 | - name: "Delete dynamic playbook" 27 | file: 28 | path: "{{ dest_file }}" 29 | state: absent 30 | -------------------------------------------------------------------------------- /collections/ansible_collections/testing/indirect_host_counting/plugins/action/produce_inc_output.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, print_function 2 | 3 | __metaclass__ = type 4 | 5 | from ansible.plugins.action import ActionBase 6 | 7 | 8 | class ActionModule(ActionBase): 9 | def run(self, tmp=None, task_vars=None): 10 | self._supports_check_mode = False 11 | 12 | result = super(ActionModule, self).run(tmp, task_vars) 13 | 14 | result['msg'] = 'This is my message, maybe it is structured?' 15 | result['my_children'] = { 16 | 'child_1': { 17 | 'changed': True, 18 | }, 19 | 'child_2': { 20 | 'changed': False, 21 | }, 22 | 'child_3': { 23 | 'grandchildren': { 24 | 'grandchild_1': { 25 | 'changed': True, 26 | } 27 | } 28 | } 29 | } 30 | result['changed'] = False 31 | return result 32 | -------------------------------------------------------------------------------- /inventories/user_plugins/inventory_plugins/fox.py: -------------------------------------------------------------------------------- 1 | from __future__ import (absolute_import, division, print_function) 2 | __metaclass__ = type 3 | 4 | DOCUMENTATION = r''' 5 | inventory: cow 6 | version_added: "2.7" 7 | short_description: What does the fox say? No one knows, error! 8 | description: 9 | - Ignores whatever you give it 10 | - You will never find out what the fox says 11 | ''' 12 | 13 | EXAMPLES = r''' 14 | # plugin: fox 15 | ''' 16 | 17 | from ansible.plugins.inventory import BaseInventoryPlugin 18 | 19 | 20 | def ancient_mystery(): 21 | raise Exception('Gering-ding-ding-ding-dingeringeding') 22 | 23 | 24 | class InventoryModule(BaseInventoryPlugin): 25 | 26 | NAME = 'fox' 27 | 28 | def parse(self, inventory, loader, host_list, cache=True): 29 | ''' doesnt parse the inventory file, but claims it did anyway ''' 30 | super(InventoryModule, self).parse(inventory, loader, host_list) 31 | self.inventory.add_host('fox') # could be used to test rollback 32 | ancient_mystery() 33 | -------------------------------------------------------------------------------- /tower_collection_smoke.j2: -------------------------------------------------------------------------------- 1 | - name: Launch a Job Template 2 | {{ collection_id }}.tower_job_launch: 3 | job_template: "Demo Job Template" 4 | register: job 5 | 6 | - assert: 7 | that: 8 | - "job is changed" 9 | - "job.status == 'pending'" 10 | 11 | - name: List jobs w/ a matching primary key 12 | {{ collection_id }}.tower_job_list: 13 | query: 14 | id: "{{ '{{' }} job.id {{ '}}' }}" 15 | register: matching_jobs 16 | 17 | - assert: 18 | that: 19 | - "{{ '{{' }} matching_jobs.count {{ '}}' }} == 1" 20 | 21 | - name: List failed jobs (which don't exist) 22 | {{ collection_id }}.tower_job_list: 23 | status: failed 24 | query: 25 | id: "{{ '{{' }} job.id {{ '}}' }}" 26 | register: successful_jobs 27 | 28 | - assert: 29 | that: 30 | - "{{ '{{' }} successful_jobs.count {{ '}}' }} == 0" 31 | 32 | - name: Get ALL result pages! 33 | {{ collection_id }}.tower_job_list: 34 | all_pages: True 35 | register: all_page_query 36 | 37 | - assert: 38 | that: 39 | - 'not all_page_query.next' 40 | -------------------------------------------------------------------------------- /inventories/dyn_inventory_test_env.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | from datetime import datetime 4 | import json 5 | import os 6 | 7 | inventory = {'all': {'vars': {'ansible_connection': 'local'}}, 8 | 'ungrouped': {'hosts': ['localhost']}, 9 | '_meta': {'hostvars': {'localhost': {'test_env': os.environ.get('TEST_ENV', False), 10 | 'current_time': str(datetime.now())}}}} 11 | 12 | 13 | def parse_args(): 14 | parser = ArgumentParser() 15 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 16 | help='List instances (default: True)') 17 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 18 | return parser.parse_args() 19 | 20 | 21 | def load_inventory(): 22 | args = parse_args() 23 | if args.list_instances: 24 | print(json.dumps(inventory, indent=4)) 25 | 26 | 27 | if __name__ == '__main__': 28 | load_inventory() 29 | -------------------------------------------------------------------------------- /inventories/script_migrations/overwrite2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # changes made relative to overwrite1.py: 5 | # - host_1 is removed from parent group (but still present in import) 6 | # - child_group2 is removed from parent group (but still present in import) 7 | # - switch1 and switch2 trade hosts 8 | # - child_switch1 and 2 trade child groups 9 | # - "will remove" host / group are removed 10 | 11 | import json 12 | 13 | print( 14 | json.dumps( 15 | { 16 | "_meta": {"hostvars": {"host_1": {}, "host_2": {}}}, 17 | "child_group": {"hosts": ["host_of_child"]}, 18 | "child_group2": {"hosts": ["host_of_child"]}, 19 | "not_child": {"hosts": ["host_of_not_child"]}, 20 | "switch1": {"hosts": ["host_switch2"]}, 21 | "switch2": {"hosts": ["host_switch1"]}, 22 | "parent_switch1": {"children": ["switch2"]}, 23 | "parent_switch2": {"children": ["switch1"]}, 24 | "parent_group": {"hosts": ["host_2"], "children": ["child_group"]}, 25 | } 26 | ) 27 | ) 28 | -------------------------------------------------------------------------------- /gather_facts_set_stats.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: true 5 | tasks: 6 | - name: set a fact man 7 | set_fact: 8 | foo: "bar" 9 | bar: 10 | a: 11 | b: 12 | - "c" 13 | - "d" 14 | cacheable: "{{ set_fact_cacheable | default(false) }}" 15 | - name: set some stats man 16 | set_stats: 17 | data: 18 | string: 'abc' 19 | integer: 123 20 | float: 1.0 21 | unicode: '竳䙭韽' 22 | boolean: true 23 | none: null 24 | list: 25 | - 'abc' 26 | - 123 27 | - 1.0 28 | - '竳䙭韽' 29 | - true 30 | - null 31 | - [] 32 | - {} 33 | object: 34 | string: 'abc' 35 | integer: 123 36 | float: 1.0 37 | unicode: '竳䙭韽' 38 | boolean: true 39 | none: null 40 | list: [] 41 | object: {} 42 | empty_list: [] 43 | empty_object: {} 44 | 45 | -------------------------------------------------------------------------------- /cloud_modules/azure_rm.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create and remove an Azure virtual machine 3 | hosts: localhost 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: Create VM 9 | azure_rm_virtualmachine: 10 | admin_username: "{{ admin_username | default('tower-qe') }}" 11 | admin_password: "{{ admin_password | default('YouSh@llNotPas5') }}" 12 | resource_group: "{{ resource_group | default('qe') }}" 13 | name: "{{ vm_name | default('tower-qe-test-vm') }}" 14 | virtual_network: "{{ virtual_network | default('qe-vnet') }}" 15 | subnet: "{{ subnet | default('default') }}" 16 | vm_size: "{{ vm_size | default('Standard_B1ls') }}" 17 | image: 18 | offer: CentOS 19 | publisher: OpenLogic 20 | sku: '7.1' 21 | version: latest 22 | tags: 23 | - azure 24 | 25 | - name: Remove VM 26 | azure_rm_virtualmachine: 27 | resource_group: "{{ resource_group | default('qe') }}" 28 | name: "{{ vm_name | default('tower-qe-test-vm') }}" 29 | state: absent 30 | tags: 31 | - azure 32 | -------------------------------------------------------------------------------- /long_task_name.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - name: testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest123 7 | debug: 8 | msg: "Hello World!" 9 | -------------------------------------------------------------------------------- /inventories/script_migrations/custom_script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import uuid 5 | 6 | unique_name = str(uuid.uuid4()) 7 | host_1 = "host_{}".format(unique_name) 8 | host_2 = "host_2_{}".format(unique_name) 9 | print( 10 | json.dumps( 11 | { 12 | "_meta": { 13 | "hostvars": { 14 | "{}".format(host_1): {"name": "{}".format(host_1)}, 15 | "{}".format(host_2): {"name": "{}".format(host_2)}, 16 | "all_have": {"name": "all_have"}, 17 | "all_have2": {"name": "all_have2"}, 18 | "all_have3": {"name": "all_have3"}, 19 | } 20 | }, 21 | "ungrouped": {"hosts": ["groupless"]}, 22 | "child_group": {"hosts": ["{}".format(host_1), "all_have"]}, 23 | "child_group2": {"hosts": ["{}".format(host_1), "all_have2"]}, 24 | "parent_group": { 25 | "hosts": ["{}".format(host_2), "all_have3"], 26 | "children": ["child_group", "child_group2"], 27 | }, 28 | } 29 | ) 30 | ) 31 | -------------------------------------------------------------------------------- /inventories/collections/ansible_collections/shanemcd/scratch/plugins/inventory/blah.py: -------------------------------------------------------------------------------- 1 | from __future__ import (absolute_import, division, print_function) 2 | __metaclass__ = type 3 | 4 | DOCUMENTATION = r''' 5 | name: blah 6 | plugin_type: inventory 7 | short_description: Prints to standard out with data including NUL character 8 | description: For use in testing processing of that character 9 | options: 10 | plugin: 11 | description: Name of the plugin 12 | required: true 13 | choices: ['blah', 'shanemcd.scratch.blah'] 14 | ''' 15 | 16 | from ansible.plugins.inventory import BaseInventoryPlugin 17 | 18 | 19 | class InventoryModule(BaseInventoryPlugin): 20 | NAME = 'blah' 21 | 22 | def verify_file(self, path): 23 | ''' 24 | Return true/false if this is possibly 25 | a valid file for this plugin to consume 26 | ''' 27 | for i in range(61): 28 | print("hi") 29 | print("\x00\x00\x00") 30 | return True 31 | 32 | def parse(self, inventory, loader, path, cache): 33 | '''Return dynamic inventory from source''' 34 | pass 35 | -------------------------------------------------------------------------------- /inventories/script_migrations/encrypted_var.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | 5 | 6 | # this is the string "artemis" encrypted with ansible-vault 7 | # direct output from: 8 | # ansible-vault encrypt_string --vault-id alan@prompt 'artemis' 9 | # (on prompt provide "password" for the vault password) 10 | encrypted_content = ( 11 | "$ANSIBLE_VAULT;1.2;AES256;alan\n" # line break required, non-obvious Ansible-ism 12 | "61346130303231633133646133646639626338323565396239396633333736653630633938323733" 13 | "6235323735363362346632353132386466396232343133340a356330376131383637393535376236" 14 | "31383561616533643835336266366263346630666335336265306139316138666561626531313864" 15 | "3161633532623966380a333433303064383831613630366137656330353833383233353561626635" 16 | "3832" 17 | ) 18 | 19 | 20 | print( 21 | json.dumps( 22 | { 23 | "_meta": { 24 | "hostvars": { 25 | "foobar": {"encrypted_var": {"__ansible_vault": encrypted_content}} 26 | } 27 | }, 28 | "ungrouped": {"hosts": ["foobar"]}, 29 | } 30 | ) 31 | ) 32 | -------------------------------------------------------------------------------- /gen_host_status_base.yml: -------------------------------------------------------------------------------- 1 | - name: A debug msg all hosts will show except for skipped ones 2 | debug: 3 | msg: "Playing {{ ansible_host }}" 4 | when: "'_skipped' not in ansible_host" 5 | 6 | - name: Hosts haven't really changed, but we will say they have 7 | debug: 8 | msg: "I am a changed host." 9 | changed_when: true 10 | when: "'_changed' in ansible_host" 11 | 12 | - name: All failhosts aboard the failboat 13 | fail: 14 | msg: "I did nothing to deserve this." 15 | when: "'_failed' in ansible_host" 16 | 17 | - name: Ignore this failure for some hosts 18 | fail: 19 | msg: "" 20 | ignore_errors: true 21 | when: "'_ignored' in ansible_host" 22 | 23 | - name: Fail and rescue - collection of tasks 24 | block: 25 | - fail: 26 | msg: "HALP!!!" 27 | when: "'_rescued' in ansible_host" 28 | rescue: 29 | - debug: msg="ε-(´・`) フ" 30 | 31 | - name: Set unreachable fact 32 | set_fact: 33 | unreachable: true 34 | when: "'_unreachable' in ansible_host" 35 | 36 | - name: Reach out to the unreachable hosts 37 | ping: 38 | vars: 39 | ansible_host: 'invalid.invalid' 40 | when: unreachable is defined and unreachable 41 | -------------------------------------------------------------------------------- /async_tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | 7 | - name: Create the async directory to prevent race conditions 8 | file: 9 | path: ~/.ansible_async 10 | state: directory 11 | run_once: true 12 | 13 | - name: Poll a sleep 14 | shell: "sleep 10" 15 | async: 30 16 | poll: 5 17 | 18 | - debug: 19 | msg: "I'm a debug message." 20 | 21 | - name: Fire and forget a slow command 22 | shell: | 23 | sleep 15 24 | touch /tmp/test_file 25 | async: 30 26 | poll: 0 27 | register: fired 28 | 29 | - debug: 30 | msg: "I'm another debug message." 31 | 32 | - name: Examine slow command 33 | async_status: jid={{ fired.ansible_job_id }} 34 | register: slow_command 35 | until: slow_command.finished 36 | retries: 20 37 | 38 | - name: Fire and forget a slow reversal 39 | shell: | 40 | sleep 10 41 | rm -f /tmp/test_file 42 | async: 30 43 | poll: 0 44 | register: fired 45 | 46 | - debug: 47 | msg: "I'm yet another debug message." 48 | 49 | - name: Examine slow reversal 50 | async_status: jid={{ fired.ansible_job_id }} 51 | register: slow_command 52 | until: slow_command.finished 53 | retries: 20 54 | -------------------------------------------------------------------------------- /inventories/dyn_inventory_test_two_env.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | from datetime import datetime 4 | import json 5 | import os 6 | 7 | # This is almost the same as dyn_inventory_test_env.py 8 | # but it reads from 2 environment variables so that using multiple 9 | # credentials with inventory sources can be tested 10 | 11 | inventory = { 12 | 'all': {'vars': {'ansible_connection': 'local'}}, 13 | 'ungrouped': {'hosts': ['localhost']}, 14 | '_meta': {'hostvars': {'localhost': { 15 | 'test_env': os.environ.get('TEST_ENV', False), 16 | 'test_env2': os.environ.get('TEST_ENV2', False), 17 | 'current_time': str(datetime.now()) 18 | }}} 19 | } 20 | 21 | 22 | def parse_args(): 23 | parser = ArgumentParser() 24 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 25 | help='List instances (default: True)') 26 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 27 | return parser.parse_args() 28 | 29 | 30 | def load_inventory(): 31 | args = parse_args() 32 | if args.list_instances: 33 | print(json.dumps(inventory, indent=4)) 34 | 35 | 36 | if __name__ == '__main__': 37 | load_inventory() 38 | -------------------------------------------------------------------------------- /cloud_modules/gce.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | connection: local 4 | gather_facts: False 5 | vars: 6 | state: "absent" 7 | zone: "us-east1-b" 8 | region: "us-east1" 9 | allow_errors: False 10 | tasks: 11 | - gcp_compute_instance: 12 | name: "this-is-an-instance-created-by-tower-qa-tests" # should not match anything 13 | state: "{{ state }}" 14 | zone: us-east1-d 15 | auth_kind: serviceaccount 16 | ignore_errors: "{{ allow_errors | bool }}" 17 | - gcp_storage_bucket: 18 | name: "qe-storage-bucket" 19 | state: "{{ state }}" 20 | ignore_errors: "{{ allow_errors | bool }}" 21 | - gcp_compute_network: 22 | name: "qe-network-instance" 23 | state: "{{ state }}" 24 | ignore_errors: "{{ allow_errors | bool }}" 25 | - gcp_compute_instance: 26 | name: "qe-compute-instance" 27 | state: "{{ state }}" 28 | zone: "{{ zone }}" 29 | ignore_errors: "{{ allow_errors | bool }}" 30 | - gcp_compute_address: 31 | name: "qe-compute-address" 32 | state: "{{ state }}" 33 | region: "{{ region }}" 34 | ignore_errors: "{{ allow_errors | bool }}" 35 | - gcp_compute_disk: 36 | name: "qe-compute-address" 37 | state: "{{ state }}" 38 | zone: "{{ zone }}" 39 | ignore_errors: "{{ allow_errors | bool }}" 40 | -------------------------------------------------------------------------------- /use_facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - debug: 7 | msg: '{{ansible_distribution}}' 8 | tags: 9 | - ansible_facts 10 | - debug: 11 | msg: '{{ansible_machine}}' 12 | tags: 13 | - ansible_facts 14 | - debug: 15 | msg: '{{ansible_system}}' 16 | tags: 17 | - ansible_facts 18 | - debug: 19 | msg: '{{ansible_date_time.time}}' 20 | tags: 21 | - ansible_facts 22 | - debug: 23 | msg: '{{string}}' 24 | tags: 25 | - custom_facts 26 | - debug: 27 | msg: '{{unicode_string}}' 28 | tags: 29 | - custom_facts 30 | - debug: 31 | msg: '{{int}}' 32 | tags: 33 | - custom_facts 34 | - debug: 35 | msg: '{{float}}' 36 | tags: 37 | - custom_facts 38 | - debug: 39 | msg: '{{bool}}' 40 | tags: 41 | - custom_facts 42 | - debug: 43 | msg: '{{null}}' 44 | tags: 45 | - custom_facts 46 | - debug: 47 | msg: '{{list}}' 48 | tags: 49 | - custom_facts 50 | - debug: 51 | msg: '{{obj}}' 52 | tags: 53 | - custom_facts 54 | - debug: 55 | msg: '{{empty_list}}' 56 | tags: 57 | - custom_facts 58 | - debug: 59 | msg: '{{empty_obj}}' 60 | tags: 61 | - custom_facts 62 | -------------------------------------------------------------------------------- /setfact_50.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Sample playbook designed to execute various tasks without spawning a python process 4 | # 5 | - hosts: all 6 | gather_facts: False 7 | tasks: 8 | - set_fact: x=0 9 | - set_fact: x=1 10 | - set_fact: x=2 11 | - set_fact: x=3 12 | - set_fact: x=4 13 | - set_fact: x=5 14 | - set_fact: x=6 15 | - set_fact: x=7 16 | - set_fact: x=8 17 | - set_fact: x=9 18 | - set_fact: x=10 19 | - set_fact: x=11 20 | - set_fact: x=12 21 | - set_fact: x=13 22 | - set_fact: x=14 23 | - set_fact: x=15 24 | - set_fact: x=16 25 | - set_fact: x=17 26 | - set_fact: x=18 27 | - set_fact: x=19 28 | - set_fact: x=20 29 | - set_fact: x=21 30 | - set_fact: x=22 31 | - set_fact: x=23 32 | - set_fact: x=24 33 | - set_fact: x=25 34 | - set_fact: x=26 35 | - set_fact: x=27 36 | - set_fact: x=28 37 | - set_fact: x=29 38 | - set_fact: x=30 39 | - set_fact: x=31 40 | - set_fact: x=32 41 | - set_fact: x=33 42 | - set_fact: x=34 43 | - set_fact: x=35 44 | - set_fact: x=36 45 | - set_fact: x=37 46 | - set_fact: x=38 47 | - set_fact: x=39 48 | - set_fact: x=40 49 | - set_fact: x=41 50 | - set_fact: x=42 51 | - set_fact: x=43 52 | - set_fact: x=44 53 | - set_fact: x=45 54 | - set_fact: x=46 55 | - set_fact: x=47 56 | - set_fact: x=48 57 | - set_fact: x=49 58 | -------------------------------------------------------------------------------- /inventories/changes_slow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import time 5 | 6 | from datetime import datetime 7 | 8 | # Same as the changes script, but has a delay to test race conditions 9 | 10 | 11 | time_val = datetime.utcnow().strftime('%Y_%m_%d_%H_%M_%S.%f') 12 | 13 | moover = "moover-{}".format(time_val) 14 | 15 | time.sleep(5) 16 | 17 | print(json.dumps({ 18 | "_meta": { 19 | "hostvars": { 20 | "change_of_vars": { 21 | "static_key": "host_dynamic_{}".format(time_val), 22 | "dynamic_{}".format(time_val): "host_static_value" 23 | }, 24 | moover: { 25 | "static_var": "static_value" 26 | } 27 | } 28 | }, 29 | "all": { 30 | "vars": { 31 | "static_inventory_key": "inventory_dynamic_{}".format(time_val), 32 | "dynamic_{}".format(time_val): "inventory_static_value" 33 | } 34 | }, 35 | "group_with_moover": { 36 | "hosts": ["change_of_vars", moover] 37 | }, 38 | "group_with_vars": { 39 | "hosts": ["change_of_vars"], 40 | "vars": { 41 | "static_group_key": "group_dynamic_{}".format(time_val), 42 | "dynamic_group_{}".format(time_val): "group_static_value" 43 | } 44 | }, 45 | "ungrouped": { 46 | "hosts": [ 47 | moover, 48 | "change_of_vars" 49 | ] 50 | } 51 | })) -------------------------------------------------------------------------------- /multivault.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ansible-playbook multivault.yml --vault-id var1@prompt --vault-id var2@prompt --vault-id dotted.id@prompt 3 | # Vault password (var1): secret1 4 | # Vault password (var2): secret2 5 | # Vault password (dotted.id): secret3 6 | 7 | - hosts: all 8 | gather_facts: false 9 | vars: 10 | first: !vault | 11 | $ANSIBLE_VAULT;1.2;AES256;first 12 | 30326539376633656433636231653132623266336338316462356132366361653566303364353335 13 | 6665626463633737666336643334353262373836613332650a353531666262636531383430363935 14 | 33633465306165393538323336323135393730383563653738666163633835383262396135353765 15 | 6238333837306332630a336538623333313636353363326666613564353666623635373432386162 16 | 3562 17 | second: !vault | 18 | $ANSIBLE_VAULT;1.2;AES256;second 19 | 34653738643565633930336534363230343562343362643432616165373034376565353833366361 20 | 6264346330376564643262643166623164323433336631360a396336353866323663613935383534 21 | 33643034373439326435373539323433313832366437303764353562653834623966663533613464 22 | 3961663934613264360a613763346638636566386461333235366335336564353935356232316265 23 | 3164 24 | tasks: 25 | - include_vars: 26 | file: utils/multivault-dotted-vars.yml 27 | when: with_dotted | default(false) | bool 28 | - debug: var=first 29 | - debug: var=second 30 | - debug: var=dotted 31 | when: with_dotted | default(false) | bool 32 | -------------------------------------------------------------------------------- /utf-8-䉪ቒ칸ⱷꯔ噂폄蔆㪗輥.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: 'A play with unicode: ¢ £ ¤ ¥' 3 | hosts: all 4 | gather_facts: false 5 | vars: 6 | test_var: 'Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ' 7 | num_hosts: 5 8 | hostnames: 9 | - 'host-#ϬϭϮϯϰ' 10 | - 'host-ͰͱͲͳʹ͵' 11 | - 'host-ΙΚΛΜΝΞ' 12 | - 'host-στυφχψ' 13 | - 'host-ϬϭϮϯϰϱ' 14 | 15 | tasks: 16 | - name: 'A task name with unicode: è é ê ë' 17 | debug: msg='hi there' 18 | 19 | - name: 'A task with unicode parameters' 20 | debug: var=test_var 21 | 22 | # € ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ Ž ‘ ’ “ ” • – — ˜ ™ š › œ ž Ÿ ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ®' 23 | 24 | - name: 'A task using with_items containing unicode' 25 | debug: msg='{{item}}' 26 | with_items: 27 | - '¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö ×' 28 | - 'Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ Ā' 29 | - 'ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ' 30 | 31 | - add_host: 32 | name: '{{hostnames}}.{{item}}' 33 | groups: 'ĪīĬĭ' 34 | ansible_connection: local 35 | host_id: '{{item}}' 36 | with_sequence: start=1 end={{num_hosts}} format=%d 37 | 38 | - name: 'A role with unicode name' 39 | hosts: all 40 | gather_facts: false 41 | roles: 42 | - { role: utf-8-䉪ቒ칸ⱷꯔ噂폄蔆㪗輥 } 43 | 44 | - name: 'A play for hosts in group: ĪīĬĭ' 45 | hosts: 'ĪīĬĭ' 46 | gather_facts: false 47 | tasks: 48 | - debug: msg='Unicode is a good thing ™' 49 | -------------------------------------------------------------------------------- /inventories/changes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import json 4 | 5 | from datetime import datetime 6 | 7 | # This is a useful script to determine what happens on an inventory import 8 | # when the contents change. By using a timestamp, we should force the values 9 | # herein to change every time the sync is done. 10 | # 11 | # There are 2 examples 12 | # - demonstrate new / old hosts by changing the hostname returned each time 13 | # which is relevant to `overwrite` 14 | # - demonstrate `overwrite_vars` by including 2 sub-examples 15 | # - variable changes its name on every import 16 | # - variable changes its value on every import 17 | 18 | 19 | time_val = datetime.utcnow().strftime('%Y_%m_%d_%H_%M_%S.%f') 20 | 21 | moover = "moover-{}".format(time_val) 22 | 23 | print(json.dumps({ 24 | "_meta": { 25 | "hostvars": { 26 | "change_of_vars": { 27 | "static_key": "host_dynamic_{}".format(time_val), 28 | "dynamic_{}".format(time_val): "host_static_value" 29 | }, 30 | moover: { 31 | "static_var": "static_value" 32 | } 33 | } 34 | }, 35 | "all": { 36 | "vars": { 37 | "static_inventory_key": "inventory_dynamic_{}".format(time_val), 38 | "dynamic_{}".format(time_val): "inventory_static_value" 39 | } 40 | }, 41 | "group_with_moover": { 42 | "hosts": ["change_of_vars", moover] 43 | }, 44 | "group_with_vars": { 45 | "hosts": ["change_of_vars"], 46 | "vars": { 47 | "static_group_key": "group_dynamic_{}".format(time_val), 48 | "dynamic_group_{}".format(time_val): "group_static_value" 49 | } 50 | }, 51 | "ungrouped": { 52 | "hosts": [ 53 | moover, 54 | "change_of_vars" 55 | ] 56 | } 57 | })) -------------------------------------------------------------------------------- /library/test_scan_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from ansible.module_utils.basic import * # noqa 7 | 8 | DOCUMENTATION = ''' 9 | --- 10 | module: scan_facts 11 | short_description: Return sample facts into facts namespace. 12 | description: 13 | - Return sample facts into facts namespace. 14 | version_added: "2.3" 15 | options: 16 | requirements: [] 17 | author: Chris Meyers, Christopher Wang 18 | ''' 19 | 20 | EXAMPLES = ''' 21 | # Example fact output: 22 | { 23 | "ansible_facts": { 24 | "bool": true, 25 | "empty_list": [], 26 | "empty_obj": {}, 27 | "float": 1.0, 28 | "int": 1, 29 | "list": ["abc", 1, 1.0, true, null, [], {}], 30 | "null": null, 31 | "obj": { 32 | "bool": true, 33 | "float": 1.0, 34 | "int": 1, 35 | "list": [], 36 | "null": null, 37 | "obj": {}, 38 | "string": "abc" 39 | }, 40 | "string": "abc", 41 | "unicode_string": "鵟犭酜귃ꔀꈛ竳䙭韽ࠔ" 42 | }, 43 | "changed": false 44 | } 45 | ''' 46 | 47 | def main(): 48 | module = AnsibleModule( 49 | argument_spec = dict()) 50 | 51 | string="abc" 52 | unicode_string="鵟犭酜귃ꔀꈛ竳䙭韽ࠔ" 53 | int=1 54 | float=1.0 55 | bool=True 56 | null=None 57 | list=["abc", 1, 1.0, True, None, [], {}] 58 | obj={"string": "abc", 59 | "int": 1, 60 | "float": 1.0, 61 | "bool": True, 62 | "null": None, 63 | "list": [], 64 | "obj": {}} 65 | empty_list=[] 66 | empty_obj={} 67 | 68 | results = dict(ansible_facts=dict(string=string, unicode_string=unicode_string, int=int, float=float, bool=bool, 69 | null=null, list=list, obj=obj, empty_list=empty_list, empty_obj=empty_obj)) 70 | module.exit_json(**results) 71 | 72 | main() 73 | -------------------------------------------------------------------------------- /test_proot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Launch a job and assert that it cannot: 3 | # - see /var/lib/awx/projects (except for self) 4 | # - see /var/lib/awx/job_status 5 | # - see /tmp/ (except for self) 6 | # - see /etc/awx/settings.py 7 | # - see /var/log/ 8 | 9 | - hosts: all 10 | gather_facts: true 11 | vars: 12 | tower_conf_dir: /etc/tower 13 | tower_tmp_dirs: 14 | - /tmp 15 | sys_log_dir: /var/log 16 | tower_projects_dir: /var/lib/awx/projects 17 | tower_job_status_dir: /var/lib/awx/job_status 18 | 19 | tasks: 20 | - command: find {{tower_tmp_dirs|join(' ')}} -mindepth 1 -maxdepth 1 -type d -regex '.*bwrap_.*_.*' 21 | register: result 22 | - debug: var=result 23 | - name: assert that only one bwrap_.*_.* tempfile is visible 24 | assert: 25 | that: 26 | - 'result.rc == 0' 27 | - 'result.stdout_lines|length <= 1' 28 | 29 | - command: find {{tower_projects_dir}}/ -mindepth 1 -maxdepth 1 -type d 30 | register: result 31 | - debug: var=result 32 | - name: assert that only one tower project directory is visible 33 | assert: 34 | that: 35 | - 'result.rc == 0' 36 | - 'result.stdout_lines|length == 1' 37 | 38 | - command: find {{tower_job_status_dir}} -mindepth 1 -maxdepth 1 -type f 39 | register: result 40 | - debug: var=result 41 | - name: assert that no job_status files are visible 42 | assert: 43 | that: 44 | - 'result.rc == 0' 45 | - 'result.stdout_lines|length == 0' 46 | 47 | - command: find {{tower_conf_dir}} -mindepth 1 -maxdepth 1 -type f 48 | ignore_errors: true 49 | register: result 50 | - debug: var=result 51 | - name: assert that no tower conf files are visible 52 | assert: 53 | that: 54 | - 'result.rc == 0' 55 | - 'result.stdout_lines|length == 0' 56 | 57 | - command: find {{sys_log_dir}} -mindepth 1 -maxdepth 1 -type f 58 | ignore_errors: true 59 | register: result 60 | - debug: var=result 61 | - name: assert that no tower log files are visible 62 | assert: 63 | that: 64 | - 'result.rc == 0' 65 | # - 'result.stdout_lines|length == 0' 66 | -------------------------------------------------------------------------------- /free_waiter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | strategy: free 6 | tasks: 7 | - action: wait_for timeout={{ 5|random }} 8 | register: waited 9 | - debug: "msg='1: {{ waited.elapsed }} seconds'" 10 | - set_fact: wait_counter={{ waited.elapsed|int }} 11 | 12 | - action: wait_for timeout={{ 5|random }} 13 | register: waited 14 | - debug: "msg='2: {{ waited.elapsed }} seconds'" 15 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 16 | 17 | - action: wait_for timeout={{ 5|random }} 18 | register: waited 19 | - debug: "msg='3: {{ waited.elapsed }} seconds'" 20 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 21 | 22 | - action: wait_for timeout={{ 5|random }} 23 | register: waited 24 | - debug: "msg='4: {{ waited.elapsed }} seconds'" 25 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 26 | 27 | - action: wait_for timeout={{ 5|random }} 28 | register: waited 29 | - debug: "msg='5: {{ waited.elapsed }} seconds'" 30 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 31 | 32 | - action: wait_for timeout={{ 5|random }} 33 | register: waited 34 | - debug: "msg='6: {{ waited.elapsed }} seconds'" 35 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 36 | 37 | - action: wait_for timeout={{ 5|random }} 38 | register: waited 39 | - debug: "msg='7: {{ waited.elapsed }} seconds'" 40 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 41 | 42 | - action: wait_for timeout={{ 5|random }} 43 | register: waited 44 | - debug: "msg='8: {{ waited.elapsed }} seconds'" 45 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 46 | 47 | - action: wait_for timeout={{ 5|random }} 48 | register: waited 49 | - debug: "msg='9: {{ waited.elapsed }} seconds'" 50 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 51 | 52 | - action: wait_for timeout={{ 5|random }} 53 | register: waited 54 | - debug: "msg='10: {{ waited.elapsed }} seconds'" 55 | - set_fact: wait_counter={{ waited.elapsed|int + wait_counter|int }} 56 | 57 | - debug: msg="{{ inventory_hostname }} waited for {{ wait_counter }} seconds." 58 | -------------------------------------------------------------------------------- /inventories/more_inventories/dyn_inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | import json 4 | 5 | inventory = {'group_four': {'hosts': ['group_four_host_0{}'.format(i) for i in range(1, 6)] 6 | + ['group_four_and_five_host_0{}'.format(i) for i in range(1, 6)] 7 | + ['group_four_five_and_six_host_0{}'.format(i) for i in range(1, 6)], 8 | 'vars': {'is_in_group_four': True}}, 9 | 'group_five': {'hosts': ['group_five_host_0{}'.format(i) for i in range(1, 6)] 10 | + ['group_four_and_five_host_0{}'.format(i) for i in range(1, 6)] 11 | + ['group_five_and_six_host_0{}'.format(i) for i in range(1, 6)] 12 | + ['group_four_five_and_six_host_0{}'.format(i) for i in range(1, 6)], 13 | 'vars': {'is_in_group_five': True}}, 14 | 'group_six': {'hosts': ['group_six_host_0{}'.format(i) for i in range(1, 6)] 15 | + ['group_five_and_six_host_0{}'.format(i) for i in range(1, 6)] 16 | + ['group_four_five_and_six_host_0{}'.format(i) for i in range(1, 6)], 17 | 'vars': {'is_in_group_six': True}}, 18 | 'all': {'vars': {'ansible_connection': 'local', 19 | 'inventories_var': True}}, 20 | 'ungrouped': {'hosts': ['ungrouped_host_{}'.format('0{}'.format(i) if len(str(i)) == 1 else i) for i in range(6, 11)]}, 21 | '_meta': {'hostvars': {'group_four_host_01': {'group_four_host_01_has_this_var': True}, 22 | 'group_five_host_01': {'group_five_host_01_has_this_var': True}, 23 | 'group_six_host_01': {'group_six_host_01_has_this_var': True}}}} 24 | 25 | def dumps(dct): 26 | return json.dumps(dct, sort_keys=True, indent=4, separators=(',', ': ')) 27 | 28 | def parse_args(): 29 | parser = ArgumentParser() 30 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 31 | help='List instances (default: True)') 32 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 33 | return parser.parse_args() 34 | 35 | 36 | def load_inventory(): 37 | args = parse_args() 38 | if args.list_instances: 39 | print(dumps(inventory)) 40 | 41 | 42 | if __name__ == '__main__': 43 | load_inventory() 44 | -------------------------------------------------------------------------------- /inventories/more_inventories/even_more_inventories/dyn_inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | import json 4 | 5 | inventory = {'group_seven': {'hosts': ['group_seven_host_0{}'.format(i) for i in range(1, 6)] 6 | + ['group_seven_and_eight_host_0{}'.format(i) for i in range(1, 6)] 7 | + ['group_seven_eight_and_nine_host_0{}'.format(i) for i in range(1, 6)], 8 | 'vars': {'is_in_group_seven': True}}, 9 | 'group_eight': {'hosts': ['group_eight_host_0{}'.format(i) for i in range(1, 6)] 10 | + ['group_seven_and_eight_host_0{}'.format(i) for i in range(1, 6)] 11 | + ['group_eight_and_nine_host_0{}'.format(i) for i in range(1, 6)] 12 | + ['group_seven_eight_and_nine_host_0{}'.format(i) for i in range(1, 6)], 13 | 'vars': {'is_in_group_eight': True}}, 14 | 'group_nine': {'hosts': ['group_nine_host_0{}'.format(i) for i in range(1, 6)] 15 | + ['group_eight_and_nine_host_0{}'.format(i) for i in range(1, 6)] 16 | + ['group_seven_eight_and_nine_host_0{}'.format(i) for i in range(1, 6)], 17 | 'vars': {'is_in_group_nine': True}}, 18 | 'all': {'vars': {'ansible_connection': 'local', 19 | 'inventories_var': True}}, 20 | 'ungrouped': {'hosts': ['ungrouped_host_{}'.format(i) for i in range(11, 16)]}, 21 | '_meta': {'hostvars': {'group_seven_host_01': {'group_seven_host_01_has_this_var': True}, 22 | 'group_eight_host_01': {'group_eight_host_01_has_this_var': True}, 23 | 'group_nine_host_01': {'group_nine_host_01_has_this_var': True}}}} 24 | 25 | def dumps(dct): 26 | return json.dumps(dct, sort_keys=True, indent=4, separators=(',', ': ')) 27 | 28 | def parse_args(): 29 | parser = ArgumentParser() 30 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 31 | help='List instances (default: True)') 32 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 33 | return parser.parse_args() 34 | 35 | 36 | def load_inventory(): 37 | args = parse_args() 38 | if args.list_instances: 39 | print(dumps(inventory)) 40 | 41 | 42 | if __name__ == '__main__': 43 | load_inventory() 44 | -------------------------------------------------------------------------------- /inventories/dyn_inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | import json 4 | 5 | inventory = {'group_one': {'hosts': ['group_one_host_0{}'.format(i) for i in range(1, 6)] 6 | + ['group_one_and_two_host_0{}'.format(i) for i in range(1, 6)] 7 | + ['group_one_two_and_three_host_0{}'.format(i) for i in range(1, 6)], 8 | 'vars': {'is_in_group_one': True, 9 | 'complex_var': [{"dir": "/opt/gwaf/logs", 10 | "sourcetype": "gwaf", 11 | "something_else": [1, 2, 3]}]}}, 12 | 'group_two': {'hosts': ['group_two_host_0{}'.format(i) for i in range(1, 6)] 13 | + ['group_one_and_two_host_0{}'.format(i) for i in range(1, 6)] 14 | + ['group_two_and_three_host_0{}'.format(i) for i in range(1, 6)] 15 | + ['group_one_two_and_three_host_0{}'.format(i) for i in range(1, 6)], 16 | 'vars': {'is_in_group_two': True}}, 17 | 'group_three': {'hosts': ['group_three_host_0{}'.format(i) for i in range(1, 6)] 18 | + ['group_two_and_three_host_0{}'.format(i) for i in range(1, 6)] 19 | + ['group_one_two_and_three_host_0{}'.format(i) for i in range(1, 6)], 20 | 'vars': {'is_in_group_three': True}}, 21 | 'all': {'vars': {'ansible_connection': 'local', 22 | 'inventories_var': True}}, 23 | 'ungrouped': {'hosts': ['ungrouped_host_0{}'.format(i) for i in range(1, 6)]}, 24 | '_meta': {'hostvars': {'group_one_host_01': {'group_one_host_01_has_this_var': True}, 25 | 'group_two_host_01': {'group_two_host_01_has_this_var': True}, 26 | 'group_three_host_01': {'group_three_host_01_has_this_var': True}}}} 27 | 28 | def parse_args(): 29 | parser = ArgumentParser() 30 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 31 | help='List instances (default: True)') 32 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 33 | return parser.parse_args() 34 | 35 | 36 | def load_inventory(): 37 | args = parse_args() 38 | if args.list_instances: 39 | print(json.dumps(inventory, indent=4)) 40 | 41 | 42 | if __name__ == '__main__': 43 | load_inventory() 44 | -------------------------------------------------------------------------------- /inventories/script_migrations/test_isolation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import json 4 | import re 5 | 6 | errors = list() 7 | 8 | # assert that only one awx_\w*_\w* tempfile is visible 9 | awx_tmp_files = [] 10 | for tmpdir in ("/tmp", "/var/tmp"): 11 | for file in os.listdir(tmpdir): 12 | awx_matches = re.search(r"awx_\w*_\w*", file) 13 | di_matches = re.search(r"runner_di_\w*", file) 14 | pi_matches = re.search(r"ansible_runner_pi_\w*", file) 15 | if awx_matches or di_matches or pi_matches: 16 | full_path = os.path.join(tmpdir, file) 17 | awx_tmp_files.append(full_path) 18 | 19 | if len(awx_tmp_files) > 1: 20 | # we would see one file -- the job directory created for this job 21 | errors.append(("Tower temporary files", awx_tmp_files)) 22 | 23 | # assert that no project directories are visible 24 | for tower_projects_dir in ("/var/lib/awx/projects", "/var/lib/tower/projects"): 25 | if not os.path.isdir(tower_projects_dir): 26 | continue 27 | files = os.listdir(tower_projects_dir) 28 | if files: 29 | files = [os.path.join(tower_projects_dir, f) for f in files] 30 | errors.append(("Tower project directories", files)) 31 | 32 | # assert that no job_status files are visible 33 | for tower_job_status_dir in ("/var/lib/awx/job_status", "/var/lib/tower/job_status"): 34 | if not os.path.isdir(tower_job_status_dir): 35 | continue 36 | files = os.listdir(tower_job_status_dir) 37 | if files: 38 | files = [os.path.join(tower_job_status_dir, f) for f in files] 39 | errors.append(("Tower job_status files", files)) 40 | 41 | # assert that no tower conf files are visible 42 | for tower_conf_dir in ("/etc/awx", "/etc/tower"): 43 | if not os.path.isdir(tower_conf_dir): 44 | continue 45 | files = os.listdir(tower_conf_dir) 46 | if files: 47 | files = [os.path.join(tower_conf_dir, f) for f in files] 48 | errors.append(("Tower config files", files)) 49 | 50 | # assert that no tower log files are visible 51 | for tower_log_dir in ("/var/log/awx", "/var/log/tower"): 52 | if not os.path.isdir(tower_log_dir): 53 | continue 54 | files = os.listdir(tower_log_dir) 55 | if files: 56 | files = [os.path.join(tower_log_dir, f) for f in files] 57 | errors.append(("Tower log files", files)) 58 | 59 | if errors: 60 | err_str = "The following errors were detected while running a proot-enabled inventory_update.\\n" 61 | for (name, files) in errors: 62 | err_str += "\\n# %s\\n" % name 63 | err_str += " - %s" % "\\n - ".join(files) 64 | 65 | raise Exception(err_str) 66 | 67 | print(json.dumps({})) 68 | -------------------------------------------------------------------------------- /inventories/metaless_dyn_inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from argparse import ArgumentParser 3 | import json 4 | 5 | inventory = {'group_one': {'hosts': ['group_one_host_0{}'.format(i) for i in range(1, 6)] 6 | + ['group_one_and_two_host_0{}'.format(i) for i in range(1, 6)] 7 | + ['group_one_two_and_three_host_0{}'.format(i) for i in range(1, 6)], 8 | 'vars': {'is_in_group_one': True, 9 | 'complex_var': [{"dir": "/opt/gwaf/logs", 10 | "sourcetype": "gwaf", 11 | "something_else": [1, 2, 3]}]}}, 12 | 'group_two': {'hosts': ['group_two_host_0{}'.format(i) for i in range(1, 6)] 13 | + ['group_one_and_two_host_0{}'.format(i) for i in range(1, 6)] 14 | + ['group_two_and_three_host_0{}'.format(i) for i in range(1, 6)] 15 | + ['group_one_two_and_three_host_0{}'.format(i) for i in range(1, 6)], 16 | 'vars': {'is_in_group_two': True}}, 17 | 'group_three': {'hosts': ['group_three_host_0{}'.format(i) for i in range(1, 6)] 18 | + ['group_two_and_three_host_0{}'.format(i) for i in range(1, 6)] 19 | + ['group_one_two_and_three_host_0{}'.format(i) for i in range(1, 6)], 20 | 'vars': {'is_in_group_three': True}}, 21 | 'all': {'vars': {'ansible_connection': 'local', 22 | 'inventories_var': True}}, 23 | 'ungrouped': {'hosts': ['ungrouped_host_0{}'.format(i) for i in range(1, 6)]}} 24 | 25 | hostvars = {'group_one_host_01': {'group_one_host_01_has_this_var': True}, 26 | 'group_two_host_01': {'group_two_host_01_has_this_var': True}, 27 | 'group_three_host_01': {'group_three_host_01_has_this_var': True}} 28 | 29 | 30 | def dumps(dct): 31 | return json.dumps(dct, sort_keys=True, indent=4, separators=(',', ': ')) 32 | 33 | 34 | def parse_args(): 35 | parser = ArgumentParser() 36 | parser.add_argument('--list', dest='list_instances', action='store_true', default=True, 37 | help='List instances (default: True)') 38 | parser.add_argument('--host', dest='requested_host', help='Get all the variables about a specific instance') 39 | return parser.parse_args() 40 | 41 | 42 | def load_inventory(): 43 | args = parse_args() 44 | if args.requested_host: 45 | print(dumps(hostvars.get(args.requested_host, {}))) 46 | elif args.list_instances: 47 | print(dumps(inventory)) 48 | else: 49 | print({}) 50 | 51 | 52 | if __name__ == '__main__': 53 | load_inventory() 54 | -------------------------------------------------------------------------------- /debug-50.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | gather_facts: false 5 | tasks: 6 | - debug: msg='01' 7 | - pause: seconds=1 8 | 9 | - debug: msg='02' 10 | - pause: seconds=1 11 | 12 | - debug: msg='03' 13 | - pause: seconds=1 14 | 15 | - debug: msg='04' 16 | - pause: seconds=1 17 | 18 | - debug: msg='05' 19 | - pause: seconds=1 20 | 21 | - debug: msg='06' 22 | - pause: seconds=1 23 | 24 | - debug: msg='07' 25 | - pause: seconds=1 26 | 27 | - debug: msg='08' 28 | - pause: seconds=1 29 | 30 | - debug: msg='09' 31 | - pause: seconds=1 32 | 33 | - debug: msg='10' 34 | - pause: seconds=1 35 | 36 | - debug: msg='11' 37 | - pause: seconds=1 38 | 39 | - debug: msg='12' 40 | - pause: seconds=1 41 | 42 | - debug: msg='13' 43 | - pause: seconds=1 44 | 45 | - debug: msg='14' 46 | - pause: seconds=1 47 | 48 | - debug: msg='15' 49 | - pause: seconds=1 50 | 51 | - debug: msg='16' 52 | - pause: seconds=1 53 | 54 | - debug: msg='17' 55 | - pause: seconds=1 56 | 57 | - debug: msg='18' 58 | - pause: seconds=1 59 | 60 | - debug: msg='19' 61 | - pause: seconds=1 62 | 63 | - debug: msg='20' 64 | - pause: seconds=1 65 | 66 | - debug: msg='21' 67 | - pause: seconds=1 68 | 69 | - debug: msg='22' 70 | - pause: seconds=1 71 | 72 | - debug: msg='23' 73 | - pause: seconds=1 74 | 75 | - debug: msg='24' 76 | - pause: seconds=1 77 | 78 | - debug: msg='25' 79 | - pause: seconds=1 80 | 81 | - debug: msg='26' 82 | - pause: seconds=1 83 | 84 | - debug: msg='27' 85 | - pause: seconds=1 86 | 87 | - debug: msg='28' 88 | - pause: seconds=1 89 | 90 | - debug: msg='29' 91 | - pause: seconds=1 92 | 93 | - debug: msg='30' 94 | - pause: seconds=1 95 | 96 | - debug: msg='31' 97 | - pause: seconds=1 98 | 99 | - debug: msg='32' 100 | - pause: seconds=1 101 | 102 | - debug: msg='33' 103 | - pause: seconds=1 104 | 105 | - debug: msg='34' 106 | - pause: seconds=1 107 | 108 | - debug: msg='35' 109 | - pause: seconds=1 110 | 111 | - debug: msg='36' 112 | - pause: seconds=1 113 | 114 | - debug: msg='37' 115 | - pause: seconds=1 116 | 117 | - debug: msg='38' 118 | - pause: seconds=1 119 | 120 | - debug: msg='39' 121 | - pause: seconds=1 122 | 123 | - debug: msg='40' 124 | - pause: seconds=1 125 | 126 | - debug: msg='41' 127 | - pause: seconds=1 128 | 129 | - debug: msg='42' 130 | - pause: seconds=1 131 | 132 | - debug: msg='43' 133 | - pause: seconds=1 134 | 135 | - debug: msg='44' 136 | - pause: seconds=1 137 | 138 | - debug: msg='45' 139 | - pause: seconds=1 140 | 141 | - debug: msg='46' 142 | - pause: seconds=1 143 | 144 | - debug: msg='47' 145 | - pause: seconds=1 146 | 147 | - debug: msg='48' 148 | - pause: seconds=1 149 | 150 | - debug: msg='49' 151 | - pause: seconds=1 152 | 153 | - debug: msg='50' 154 | - pause: seconds=1 155 | -------------------------------------------------------------------------------- /dynamic_inventory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: add hosts to inventory 3 | hosts: all 4 | vars: 5 | num_hosts: 10 6 | tasks: 7 | - name: create inventory 8 | add_host: 9 | name: 'host-{{item}}' 10 | groups: dynamic 11 | ansible_connection: local 12 | host_id: '{{item}}' 13 | with_sequence: start=1 end={{num_hosts}} format=%d 14 | notify: 15 | - single host handler 16 | 17 | handlers: 18 | - name: single host handler 19 | command: 'true' 20 | 21 | 22 | - name: various task responses on dynamic inventory 23 | hosts: 'dynamic' 24 | tasks: 25 | - name: fail even numbered hosts 26 | command: 'false' 27 | when: host_id|int % 2 == 0 28 | - name: skip multiples of 3 29 | command: 'true' 30 | when: host_id|int % 3 != 0 31 | - name: all skipped 32 | command: 'true' 33 | when: false 34 | - name: all changed 35 | command: 'true' 36 | notify: 37 | - changed handler 38 | - name: all ok 39 | command: 'true' 40 | changed_when: false 41 | notify: 42 | # this will never notify since the task never is changed: true 43 | - ok handler 44 | handlers: 45 | - name: ok handler 46 | command: 'false' 47 | - name: changed handler 48 | command: 'true' 49 | notify: another changed handler 50 | - name: yet another changed handler 51 | command: 'true' 52 | - name: another changed handler 53 | command: 'true' 54 | 55 | 56 | - name: shrink inventory to 1 host 57 | hosts: 'dynamic' 58 | tasks: 59 | - name: fail all but 1 60 | command: 'false' 61 | when: host_id|int != 1 62 | 63 | 64 | - name: 1 host play 65 | hosts: 'host-1' 66 | gather_facts: false 67 | tasks: 68 | - name: pass 69 | command: 'true' 70 | - name: ok 71 | command: 'true' 72 | changed_when: false 73 | - name: ignored 74 | command: 'false' 75 | ignore_errors: true 76 | 77 | 78 | - name: fail remaining dynamic group 79 | hosts: all 80 | gather_facts: true 81 | tasks: 82 | - name: fail 83 | command: 'false' 84 | when: inventory_hostname == 'host-1' 85 | 86 | 87 | - name: add hosts to inventory 88 | hosts: all 89 | vars: 90 | num_hosts: 10 91 | tasks: 92 | - name: add dynamic inventory 93 | add_host: 94 | name: 'new-host-{{item}}' 95 | groups: dynamic 96 | ansible_connection: local 97 | host_id: '{{item}}' 98 | with_sequence: start=1 end={{(num_hosts|int / 2)|int}} format=%d 99 | - name: add unreachable inventory 100 | add_host: 101 | name: 'unreachable-host-{{item}}' 102 | groups: unreachable 103 | ansible_connection: ssh 104 | host_id: '{{item}}' 105 | with_sequence: start={{(num_hosts|int / 2)|int + 1}} end={{num_hosts}} format=%d 106 | - name: add more_unreachable inventory 107 | add_host: 108 | name: 'more-unreachable-host-{{item}}' 109 | groups: more-unreachable 110 | ansible_connection: ssh 111 | host_id: '{{item}}' 112 | with_sequence: start={{(num_hosts|int / 2)|int + 1}} end={{num_hosts}} format=%d 113 | 114 | 115 | - name: some unreachable, some changed, some skipped 116 | hosts: 'dynamic:unreachable' 117 | gather_facts: false 118 | tasks: 119 | - name: all changed with items 120 | command: 'true' 121 | when: host_id|int % 5 == 0 122 | 123 | 124 | - name: no matching hosts 125 | hosts: no_hosts_will_ever_match_this_string 126 | 127 | 128 | - name: gather facts fail 129 | hosts: unreachable 130 | gather_facts: true 131 | 132 | 133 | - name: some gather facts fail 134 | hosts: more-unreachable:dynamic 135 | gather_facts: true 136 | tasks: 137 | - name: skip this task 138 | command: 'false' 139 | when: false 140 | 141 | 142 | - name: no tasks, just the facts 143 | hosts: all 144 | -------------------------------------------------------------------------------- /become_plugins/custom_plugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright: (c) 2018, Ansible Project 3 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 4 | from __future__ import (absolute_import, division, print_function) 5 | __metaclass__ = type 6 | 7 | DOCUMENTATION = """ 8 | become: custom_plugin 9 | short_description: Substitute User DO 10 | description: 11 | - This become plugins allows your remote/login user to execute commands as another user via the sudo utility. 12 | author: ansible (@core) 13 | version_added: "2.8" 14 | options: 15 | become_user: 16 | description: User you 'become' to execute the task 17 | default: root 18 | ini: 19 | - section: privilege_escalation 20 | key: become_user 21 | - section: sudo_become_plugin 22 | key: user 23 | vars: 24 | - name: ansible_become_user 25 | - name: ansible_sudo_user 26 | env: 27 | - name: ANSIBLE_BECOME_USER 28 | - name: ANSIBLE_SUDO_USER 29 | become_exe: 30 | description: Sudo executable 31 | default: sudo 32 | ini: 33 | - section: privilege_escalation 34 | key: become_exe 35 | - section: sudo_become_plugin 36 | key: executable 37 | vars: 38 | - name: ansible_become_exe 39 | - name: ansible_sudo_exe 40 | env: 41 | - name: ANSIBLE_BECOME_EXE 42 | - name: ANSIBLE_SUDO_EXE 43 | become_flags: 44 | description: Options to pass to sudo 45 | default: -H -S -n 46 | ini: 47 | - section: privilege_escalation 48 | key: become_flags 49 | - section: sudo_become_plugin 50 | key: flags 51 | vars: 52 | - name: ansible_become_flags 53 | - name: ansible_sudo_flags 54 | env: 55 | - name: ANSIBLE_BECOME_FLAGS 56 | - name: ANSIBLE_SUDO_FLAGS 57 | become_pass: 58 | description: Password to pass to sudo 59 | required: False 60 | vars: 61 | - name: ansible_become_password 62 | - name: ansible_become_pass 63 | - name: ansible_sudo_pass 64 | env: 65 | - name: ANSIBLE_BECOME_PASS 66 | - name: ANSIBLE_SUDO_PASS 67 | ini: 68 | - section: sudo_become_plugin 69 | key: password 70 | """ 71 | 72 | 73 | from ansible.plugins.become import BecomeBase 74 | 75 | 76 | class BecomeModule(BecomeBase): 77 | 78 | name = 'custom_plugin' 79 | 80 | # messages for detecting prompted password issues 81 | fail = ('Sorry, try again.',) 82 | missing = ('Sorry, a password is required to run custom_plugin', 'custom_plugin: a password is required') 83 | 84 | def build_become_command(self, cmd, shell): 85 | super(BecomeModule, self).build_become_command(cmd, shell) 86 | 87 | if not cmd: 88 | return cmd 89 | 90 | becomecmd = self.get_option('become_exe') or self.name 91 | 92 | flags = self.get_option('become_flags') or '' 93 | prompt = '' 94 | if self.get_option('become_pass'): 95 | self.prompt = '[custom_plugin via ansible, key=%s] password:' % self._id 96 | if flags: # this could be simplified, but kept as is for now for backwards string matching 97 | flags = flags.replace('-n', '') 98 | prompt = '-p "%s"' % (self.prompt) 99 | 100 | user = self.get_option('become_user') or '' 101 | if user: 102 | user = '-u %s' % (user) 103 | 104 | return ' '.join([becomecmd, flags, prompt, user, self._build_success_command(cmd, shell)]) 105 | -------------------------------------------------------------------------------- /cloud_modules/README.md: -------------------------------------------------------------------------------- 1 | ### Cloud module testing 2 | 3 | These modules are aiming to enable various layers of testing: 4 | 5 | - presence of dependencies 6 | - correct credential schema was applied 7 | - effective credentials have been applied 8 | - successful execution 9 | - change to infrastructure was made 10 | 11 | This doc contains some brief usage notes. 12 | 13 | The ambitions of these playbooks do not go as far as changing infrastructure, 14 | and that testing already lives elsewhere. 15 | 16 | #### Dependency sufficiency 17 | 18 | Here is an example of running without a needed dependency: 19 | 20 | ``` 21 | $ ansible-playbook -i localhost, cloud_modules/aws.yml 22 | 23 | PLAY [Test use of credentials with cloud module, taken from Ansible docs] ************************************************************************************************************* 24 | 25 | TASK [Provision a set of instances (credential_type=aws)] ***************************************************************************************************************************** 26 | fatal: [localhost]: FAILED! => {"changed": false, "msg": "boto required for this module"} 27 | to retry, use: --limit @/Users/alancoding/Documents/repos/jlaska-ansible-playbooks/cloud_modules/aws.retry 28 | 29 | PLAY RECAP **************************************************************************************************************************************************************************** 30 | localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 31 | ``` 32 | 33 | If you are running from 34 | a virtual environment, you may need to specify interpreter. 35 | Here is an example of running the playbook with the proper dependencies 36 | installed, but no attempt to specify credentials: 37 | 38 | ``` 39 | $ ansible-playbook -i localhost, cloud_modules/aws.yml -e ansible_python_interpreter=$(which python) 40 | 41 | PLAY [Test use of credentials with cloud module, taken from Ansible docs] ***** 42 | 43 | TASK: [Provision a set of instances (credential_type=aws)] ******************** 44 | failed: [localhost] => {"failed": true} 45 | msg: Either region or ec2_url must be specified 46 | 47 | FATAL: all hosts have already failed -- aborting 48 | 49 | PLAY RECAP ******************************************************************** 50 | to retry, use: --limit @/Users/alancoding/aws.retry 51 | 52 | localhost : ok=0 changed=0 unreachable=0 failed=1 53 | ``` 54 | 55 | (note: this now constitutes an "incorrectly parameterized credentials" case) 56 | 57 | In this example, the boto dependency, needed for the AWS modules, was 58 | installed inside of the active virtual environment, 59 | so it did not produce an error due to the dependency. However, it 60 | did produce an error because insufficient credentials were given. 61 | 62 | #### Credential parameters 63 | 64 | Example of incorrectly parameterized credentials: 65 | 66 | ``` 67 | $ ansible-playbook -i localhost, cloud_modules/vmware.yml -e ansible_python_interpreter=$(which python) 68 | 69 | PLAY [Test use of credentials with cloud module, taken from Ansible docs] ************************************************************************************************************* 70 | 71 | TASK [VMWare Clone the template (credential_type=vmware)] ***************************************************************************************************************************** 72 | fatal: [localhost]: FAILED! => {"changed": false, "msg": "Hostname parameter is missing. Please specify this parameter in task or export environment variable like 'export VMWARE_HOST=ESXI_HOSTNAME'"} 73 | to retry, use: --limit @/Users/alancoding/Documents/repos/jlaska-ansible-playbooks/cloud_modules/vmware.retry 74 | 75 | PLAY RECAP **************************************************************************************************************************************************************************** 76 | localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 77 | ``` 78 | 79 | Example of parameterized, but incorrect, credentials: 80 | 81 | ``` 82 | $ VMWARE_HOST=ESXI_HOSTNAME VMWARE_USER=ESXI_USERNAME VMWARE_PASSWORD=ESXI_PASSWORD ansible-playbook -i localhost, cloud_modules/vmware.yml -e ansible_python_interpreter=$(which python) 83 | 84 | PLAY [Test use of credentials with cloud module, taken from Ansible docs] ************************************************************************************************************* 85 | 86 | TASK [VMWare Clone the template (credential_type=vmware)] ***************************************************************************************************************************** 87 | fatal: [localhost]: FAILED! => {"changed": false, "msg": "Unknown error while connecting to vCenter or ESXi API at ESXI_HOSTNAME:443 : [Errno 8] nodename nor servname provided, or not known"} 88 | to retry, use: --limit @/Users/alancoding/Documents/repos/jlaska-ansible-playbooks/cloud_modules/vmware.retry 89 | 90 | PLAY RECAP **************************************************************************************************************************************************************************** 91 | localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 92 | ``` 93 | 94 | #### Credential functionality 95 | 96 | If credentials are correct, the playbooks should succeed, as long as `state` 97 | isn't changed. These playbooks are not intended to make an actual change 98 | to the targeted infrastructure. 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . --------------------------------------------------------------------------------