{"id":19601546,"url":"https://github.com/berttejeda/ansible-taskrunner","last_synced_at":"2025-04-27T17:32:00.496Z","repository":{"id":35819747,"uuid":"197024683","full_name":"berttejeda/ansible-taskrunner","owner":"berttejeda","description":"Ansible Taskrunner - ansible-playbook wrapper with YAML-abstracted python click cli options!","archived":false,"fork":false,"pushed_at":"2024-08-27T02:59:38.000Z","size":709,"stargazers_count":17,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-09-27T17:08:46.088Z","etag":null,"topics":["ansible","ansible-playbook","bash","cli","click","playbook","polyglot","python","ruby","subprocess","task-runner","wrapper","yaml"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/berttejeda.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.rst","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-15T15:24:14.000Z","updated_at":"2024-08-27T02:59:42.000Z","dependencies_parsed_at":"2024-08-27T04:25:07.735Z","dependency_job_id":null,"html_url":"https://github.com/berttejeda/ansible-taskrunner","commit_stats":{"total_commits":293,"total_committers":4,"mean_commits":73.25,"dds":"0.31058020477815695","last_synced_commit":"809bab7184ff8696ebced697da179de562c1d38c"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berttejeda%2Fansible-taskrunner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berttejeda%2Fansible-taskrunner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berttejeda%2Fansible-taskrunner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berttejeda%2Fansible-taskrunner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/berttejeda","download_url":"https://codeload.github.com/berttejeda/ansible-taskrunner/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224076326,"owners_count":17251729,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-playbook","bash","cli","click","playbook","polyglot","python","ruby","subprocess","task-runner","wrapper","yaml"],"created_at":"2024-11-11T09:18:52.850Z","updated_at":"2024-11-11T09:18:53.669Z","avatar_url":"https://github.com/berttejeda.png","language":"Python","readme":"\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\r\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\r\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\r\n\r\n- [Overview](#overview)\r\n- [TL;DR](#tldr)\r\n- [Use case and example](#use-case-and-example)\r\n    - [Given](#given)\r\n    - [The Challenge](#the-challenge)\r\n    - [Investigation](#investigation)\r\n    - [Assessment](#assessment)\r\n    - [Proposed Solution](#proposed-solution)\r\n- [Technical Details](#technical-details)\r\n- [Creating a task manifest file](#creating-a-task-manifest-file)\r\n    - [Add the hosts block](#add-the-hosts-block)\r\n    - [Add the vars block](#add-the-vars-block)\r\n    - [Populate the vars block - defaults](#populate-the-vars-block---defaults)\r\n    - [Populate the vars block - define global options](#populate-the-vars-block---define-global-options)\r\n    - [Populate the vars block - define subcommands](#populate-the-vars-block---define-subcommands)\r\n      - [Populate the vars block - cli options - mapped variables](#populate-the-vars-block---cli-options---mapped-variables)\r\n    - [Populate the vars block - help/message](#populate-the-vars-block---helpmessage)\r\n    - [Populate the vars block - embedded shell functions](#populate-the-vars-block---embedded-shell-functions)\r\n      - [More about embedded shell functions](#more-about-embedded-shell-functions)\r\n        - [Bash example:](#bash-example)\r\n        - [Python example:](#python-example)\r\n        - [Ruby example:](#ruby-example)\r\n    - [Populate the vars block - dynamic inventory expression](#populate-the-vars-block---dynamic-inventory-expression)\r\n    - [Populate the vars block - inventory file](#populate-the-vars-block---inventory-file)\r\n    - [Add tasks](#add-tasks)\r\n- [Usage Examples](#usage-examples)\r\n- [Installation](#installation)\r\n    - [More Examples](#more-examples)\r\n- [Appendix](#appendix)\r\n    - [The Options Separator](#the-options-separator)\r\n    - [Bastion Mode](#bastion-mode)\r\n    - [Special Variables](#special-variables)\r\n      - [ansible_playbook_command](#ansible_playbook_command)\r\n      - [pre_execution](#pre_execution)\r\n      - [post_execution](#post_execution)\r\n      - [environment_vars](#environment_vars)\r\n        - [ANSIBLE_ Variables](#ansible_-variables)\r\n      - [cli_provider](#cli_provider)\r\n      - [__ansible_run_flags__](#__ansible_run_flags__)\r\n      - [__tasks_file__](#__tasks_file__)\r\n      - [__command__](#__command__)\r\n    - [Mutually Exclusive Options](#mutually-exclusive-options)\r\n    - [Cloned subcommands](#cloned-subcommands)\r\n    - [Simple Templating](#simple-templating)\r\n    - [Single-Executable Releases](#single-executable-releases)\r\n    - [Unit Testing](#unit-testing)\r\n- [TODO - Add more tests!](#todo---add-more-tests)\r\n- [License and Credits](#license-and-credits)\r\n\r\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\r\n\r\n\r\n  \u003cdiv align=\"center\"\u003e\r\n    \u003ch1\u003eATTENTION\u003c/h1\u003e\r\n    \u003cp\u003eI'm rewriting this tool in Go\u003c/p\u003e\r\n    \u003cp\u003eNew Repo: https://github.com/berttejeda/bert.tasks\u003c/p\u003e\r\n  \u003c/div\u003e\r\n\r\n\r\n\u003ca name=\"top\"\u003e\u003c/a\u003e\r\n\u003ca name=\"overview\"\u003e\u003c/a\u003e\r\n\r\n# Overview\r\n\r\n*ansible-taskrunner* is a cli app that is essentially an ansible wrapper.\r\n\r\nIt reads an ansible playbook file as its input, which serves as a _task manifest_.\r\n\r\nIf no task manifest is specified, the app will search for 'Taskfile.yaml' in the current working directory.\r\n\r\nThe inspiration for the tool comes from the gnu make command, which operates in similar fashion, i.e.\r\n\r\n- A Makefile defines available build steps\r\n- The make command consumes the Makefile at runtime and exposes these steps as command-line options\r\n\r\nIf you are running this tool from Windows, please read the section on [Bastion Mode](#bastion_mode)\r\n\r\n# TL;DR\r\n\r\n- Ever wanted to add custom switches to the `ansible-playbook` command? Something like this:\u003cbr /\u003e \r\n`ansible-playbook -i myinventory.txt -d dbhost1 -w webhost1 -t value1 myplaybook.yaml`\r\n- Well, you can through the use of an ansible-playbook wrapper\r\n- That's where `tasks` comes in:\u003cbr /\u003e\r\n`tasks -s -b bar -f foo1`\u003cbr /\u003e\r\ntranslates to:\u003cbr /\u003e\r\n`ansible-playbook -i /tmp/ansible-inventory16xdkrjd.tmp.ini \\\r\n-e \"{'some_foo_variable':'foo1'}\" -e \"{'some_bar_variable':'bar'}\" -e \"{'playbook_targets':'local'}\" Taskfile.yaml`\r\n\r\n1. Jump down to the [usage examples](#usage-examples) to see this in action\r\n2. Review the [installation](#installation) instructions if you want to test-drive it\r\n3. Read on if you want to dig deeper into the tool\r\n\r\n\u003ca name=\"use-case-and-example\"\u003e\u003c/a\u003e\r\n\r\n# Use case and example\r\n\r\n\u003ca name=\"given\"\u003e\u003c/a\u003e\r\n\r\n## Given\r\n\r\n1. An enterprise-grade application named contoso-app\r\n2. Multiple teams:\r\n    - Development\r\n    - Engineering\r\n    - DBA\r\n    - Operations\r\n    - QA\r\n3. Ansible is the primary means of invoking business and operational processes across the numerous environments\r\n\r\n\u003ca name=\"the-challenge\"\u003e\u003c/a\u003e\r\n\r\n## The Challenge\r\n\r\nYou must ensure all teams adopt a standardized approach to running ansible workloads\r\n\r\n\u003ca name=\"investigation\"\u003e\u003c/a\u003e\r\n\r\n## Investigation\r\n\r\nUpon investigating the current approach, you observe the following: \r\n\r\n- Users tend to create wrapper scripts that call the ansible-playbook command\r\n- These scripts don't follow any naming convention, as you've noted:\r\n  - run.sh\r\n  - start.sh\r\n  - playbook.sh\r\n- These shell scripts have common attributes:\r\n  - Dynamically populate ansible-playbook variables via the --extra-vars option\r\n  - Dynamically creating ansible inventories\r\n  - Performing pre/post-flight tasks\r\n  - Providing a command-line interface\r\n\r\n\u003ca name=\"assessment\"\u003e\u003c/a\u003e\r\n\r\n## Assessment\r\n\r\nAdvantages to the above approach:\r\n- Quick-n-dirty, anyone can get started relatively quickly with writing ansible automation\r\n\r\nDisadvantages:\r\n- Lack of standards: \r\n- Leads to difficulty in collaboration and code refactoring\r\n- Decreased re-usability of codebase\r\n  - This design encourages standalone playbooks\r\n  - Makes it more difficult to package actions as roles\r\n  - Duplicate efforts across codebase\r\n\r\n\u003ca name=\"proposed-solution\"\u003e\u003c/a\u003e\r\n\r\n## Proposed Solution\r\n\r\nEmploy a pre-execution script that operates at a layer above the `ansible-playbook` command:\r\n\r\n- Accomplishes the same as the above, but in more uniform manner\r\n- Support for custom command-line parameters/flags\r\n- Dynamic inventory expression\r\n- Embedded shell functions\r\n\r\nAdvantages to this approach:\r\n\r\n- Easier to manage\r\n  - If you know YAML and Ansible, you can get started relatively quickly with writing ansible automation\r\n- Single executable (/usr/local/bin/tasks)\r\n\r\nDisadvantages:\r\n\r\n- Target ansible controller needs to have the `tasks` command installed\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"technical-details\"\u003e\u003c/a\u003e\r\n\r\n# Technical Details\r\n\r\nAs stated in the [overview](#overview), this tool functions much like the *make* command in that \r\nit accepts an input file that essentially extends its cli options.\r\n\r\nWe create a specially formatted ansible-playbook that serves as a task manifest file (by default, Taskfile.yaml).\r\n\r\nThis task manifest file:\r\n\r\n- Extends the `tasks` command\r\n- Is a valid ansible playbook (Taskfile.yaml), and can thus be launched with the `ansible-playbook` command\r\n- Variables available to the pre-execution phase are also available to the ansible execution phase\r\n\r\n\u003ca name=\"creating-a-task-manifest-file\"\u003e\u003c/a\u003e\r\n\r\n# Creating a task manifest file\r\n\r\nIn the following sections, we'll be building a sample manifest/playbook.\r\n\r\nStart by opening up your favorite text/IDE/editor and creating \r\na new _task manifest file_ named *Taskfile.yaml*.\r\n\r\n\u003ca name=\"add-the-hosts-block\"\u003e\u003c/a\u003e\r\n\r\n## Add the hosts block\r\n\r\nAdd hosts, gather_facts, etc:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n\u003ca name=\"add-the-vars-block\"\u003e\u003c/a\u003e\r\n\r\n## Add the vars block\r\n\r\nRemember, the task runner will ultimately be calling the `ansible-playbook` command against \r\nthis very same file, \u003cbr /\u003eso it must be a valid ansible playbook.\r\n\r\nLet's add the 'vars' block, which allows us to populate some default values:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n### The vars block\r\n  vars:\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n\u003ca name=\"populate-the-vars-block---defaults\"\u003e\u003c/a\u003e\r\n\r\n## Populate the vars block - defaults\r\n\r\nLet's add some default variables to the playbook:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cbr /\u003eAs you can see, we've defined a number of variables holding different values.\r\n\r\nThe rules for evaluation of these are as follows:\u003cbr /\u003e\u003cbr /\u003e\r\n\r\n\r\n```\r\nVariable                                     | Ansible Evaluation      | Shell Function Evaluation\r\n-------------------------------------------- | ----------------------- | -----------------------\r\nstr_var: value1                              | String                  | String\r\nbool_var: True                               | Boolean                 | String\r\nnum_var: 3                                   | Integer                 | Integer\r\nmultiline_var: |                             | Multiline String        | String (heredoc)\r\n  This is a multi-line value                 |                         |\r\n  of type string                             |                         |\r\nlist_var:                                    | List Object             | String (heredoc)\r\n  - item1                                    |                         |\r\n  - item2                                    |                         |\r\ndict_var:                                    | Dictionary Object       | JSON String (heredoc)\r\n  key1: somevalue1                           |                         |\r\n  key2: somevalue2                           |                         |\r\nshell_var: $(grep somestring /some/file.txt) | String                  | Depends on output\r\n```\r\n\r\nAdditionally, arguments supplied from the command-line conform\u003cbr /\u003e\r\nto the type specified in the options definition, with \"string\" being the default type.\r\n\r\n[Back To Top](#top)\r\n\r\n\u003ca name=\"populate-the-vars-block---define-global-options\"\u003e\u003c/a\u003e\r\n## Populate the vars block - define global options\r\n\r\nGlobal options are available to all subcommands.\r\n\r\nThese are defined under the `vars.globals.options` key.\r\n\r\nLet's add a simple example:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable\r\n\r\n```  \r\n\u003c/details\u003e\r\n\r\n\u003ca name=\"populate-the-vars-block---define-subcommands\"\u003e\u003c/a\u003e\r\n## Populate the vars block - define subcommands\r\n\r\nNext, we define the available subcommands and their options.\r\n\r\nLet's add a sub-command named `run` along with its command-line options:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    ### Global Options Block\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable    \r\n    ### The commands block\r\n    commands:\r\n      run:\r\n        options:\r\n          foo:\r\n            help: \"This is some foo option\"\r\n            short: -f\r\n            long: --foo\r\n            type: choice\r\n            var: some_foo_variable\r\n            required: True\r\n            not_required_if: \r\n              - some_bar_variable\r\n            options:\r\n              - foo1\r\n              - foo2\r\n          bar:\r\n            help: \"This is some bar option\"\r\n            short: -b\r\n            long: --bar \r\n            type: str\r\n            var: some_bar_variable\r\n            required: False\r\n            required_if: \r\n              - hello\r\n              - some_baz_variable\r\n          baz:\r\n            help: \"This is some baz option\"\r\n            short: -z\r\n            long: --baz\r\n            type: str\r\n            var: some_baz_variable\r\n            required: False\r\n            mutually_exclusive_with: \r\n              - some_bar_variable\r\n              - some_foo_variable\r\n          envvar:\r\n            help: \"The value for this argument can be derived from an Environmental Variable\"\r\n            short: -E\r\n            long: --env-var\r\n            type: str\r\n            var: env_var\r\n            env_var: SOME_ENVIRONMENT_VARIABLE\r\n            env_var_show: True\r\n          num:\r\n            help: \"This is a numeric argument\"\r\n            short: -n\r\n            long: --number\r\n            var: some_num_variable\r\n            type: int\r\n            required: False \r\n            env_var_show: True\r\n          targets:\r\n            help: \"Playbook targets\"\r\n            short: -t\r\n            long: --targets\r\n            type: str\r\n            var: playbook_targets\r\n            required: True\r\n          multiple:\r\n            help: |-\r\n              This option can be specified multiple times\r\n            short: -m\r\n            long: --multiple\r\n            type: str\r\n            var: multiple_arg\r\n            allow_multiple: True\r\n          some_switch:\r\n            help: |-\r\n              This is some boolean option, behaves like Click's switches,\r\n              holds the value of True if specified\r\n              see: https://github.com/pallets/click\r\n            short: -s\r\n            long: --some-switch\r\n            is_flag: true\r\n            var: some_switch\r\n            required: True\r\n          say_hello:\r\n            help: \"Invoke the 'hello' embedded shell function\"\r\n            short: -hello\r\n            long: --say-hello\r\n            type: str\r\n            var: hello\r\n            is_flag: True\r\n          say_goodbye:\r\n            help: \"Invoke the 'goodbye' embedded shell function\"\r\n            short: -goodbye\r\n            long: --say-goodbye\r\n            type: str\r\n            var: goodbye\r\n            is_flag: True\r\n          hidden_option:\r\n            help: \"This is a hidden option\"\r\n            short: -O\r\n            long: --hidden-option\r\n            is_hidden: True\r\n            type: str\r\n            var: hidden\r\n            is_flag: True            \r\n          verbose:\r\n            help: |-\r\n              This is a sample paramter that supports counting, as with:\r\n              -v, -vv, -vvv, which would evaluate to 1, 2, and 3, respectively\r\n            short: -v\r\n            allow_counting: True\r\n            var: verbosity \r\n```   \r\n\u003c/details\u003e\r\n\r\n\u003cbr /\u003e\r\n\r\nAs you can see, commands are defined via YAML, and the syntax is mostly self-explanatory.\r\n\r\nCurrently, the parameters available to any given option are \u003cbr /\u003e\r\nconsistent with click version 8.1.x, see [API — Click Documentation (8.1.x)](https://click.palletsprojects.com/en/8.1.x/api/)\r\n\r\n**Important Notes**: \r\n\r\n- An option's _var_ key:\r\n    - In the case of standard options, this variable holds the value of the arguments passed to the option\r\n    - In the case of flags/switches, this variable is a Boolean\r\n    - The variable is available during the entire runtime\r\n- In the above example, the `-hello` and `-goodbye` options point to special mapped\u003cbr /\u003e\r\n  variables that themselves map to corresponding shell functions defined in the subcommand's\u003cbr /\u003e\r\n  functions directive. We'll discuss this more in section [embedded-shell-functions](#embedded-shell-functions).\r\n\r\n\u003ca name=\"populate-the-vars-block---cli-options---mapped-variables\"\u003e\u003c/a\u003e\r\n\r\n### Populate the vars block - cli options - mapped variables\r\n\r\nAs I mentioned before, the above mapped variables can be used **during runtime**.\u003cbr /\u003e\r\nThat is, they can be referenced in any defined shell functions, \u003cbr /\u003e\r\ndynamic inventory expression logic, as well as during ansible execution.\r\n\r\nConsider the `-f|-foo` from the example.\r\n\r\nWhatever argument you pass to this option becomes the value for the mapped variable `some_foo_variable`.\r\n\r\nAgain, this variable is made available to the underlying subprocess call, and thus to ansible.\r\n\r\nSo when we call the tasks command like so `tasks run -f foo1`, the value for the `some_foo_variable` becomes `foo`.\r\n\r\n\u003ca name=\"populate-the-vars-block---helpmessage\"\u003e\u003c/a\u003e\r\n\r\n## Populate the vars block - help/message\r\n\r\nNext, we add the help/message section:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    ### Global Options Block\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable \r\n    ### The commands block\r\n    commands:\r\n      run:\r\n        options:\r\n          foo:\r\n            help: \"This is some foo option\"\r\n            short: -f\r\n            long: --foo\r\n            type: choice\r\n            var: some_foo_variable\r\n            required: True\r\n            not_required_if: \r\n              - some_bar_variable\r\n            options:\r\n              - foo1\r\n              - foo2\r\n          bar:\r\n            help: \"This is some bar option\"\r\n            short: -b\r\n            long: --bar \r\n            type: str\r\n            var: some_bar_variable\r\n            required: False\r\n            required_if: \r\n              - hello\r\n              - some_baz_variable\r\n          baz:\r\n            help: \"This is some baz option\"\r\n            short: -z\r\n            long: --baz\r\n            type: str\r\n            var: some_baz_variable\r\n            required: False\r\n            mutually_exclusive_with: \r\n              - some_bar_variable\r\n              - some_foo_variable\r\n          envvar:\r\n            help: \"The value for this argument can be derived from an Environmental Variable\"\r\n            short: -E\r\n            long: --env-var\r\n            type: str\r\n            var: env_var\r\n            env_var: SOME_ENVIRONMENT_VARIABLE\r\n            env_var_show: True\r\n          num:\r\n            help: \"This is a numeric argument\"\r\n            short: -n\r\n            long: --number\r\n            var: some_num_variable\r\n            type: int\r\n            required: False \r\n            env_var_show: True\r\n          targets:\r\n            help: \"Playbook targets\"\r\n            short: -t\r\n            long: --targets\r\n            type: str\r\n            var: playbook_targets\r\n            required: True\r\n          multiple:\r\n            help: |-\r\n              This option can be specified multiple times\r\n            short: -m\r\n            long: --multiple\r\n            type: str\r\n            var: multiple_arg\r\n            allow_multiple: True\r\n          some_switch:\r\n            help: |-\r\n              This is some boolean option, behaves like Click's switches,\r\n              holds the value of True if specified\r\n              see: https://github.com/pallets/click\r\n            short: -s\r\n            long: --some-switch\r\n            is_flag: true\r\n            var: some_switch\r\n            required: True\r\n          say_hello:\r\n            help: \"Invoke the 'hello' embedded shell function\"\r\n            short: -hello\r\n            long: --say-hello\r\n            type: str\r\n            var: hello\r\n            is_flag: True\r\n          say_goodbye:\r\n            help: \"Invoke the 'goodbye' embedded shell function\"\r\n            short: -goodbye\r\n            long: --say-goodbye\r\n            type: str\r\n            var: goodbye\r\n            is_flag: True\r\n          hidden_option:\r\n            help: \"This is a hidden option\"\r\n            short: -O\r\n            long: --hidden-option\r\n            is_hidden: True\r\n            type: str\r\n            var: hidden\r\n            is_flag: True            \r\n          verbose:\r\n            help: |-\r\n              This is a sample paramter that supports counting, as with:\r\n              -v, -vv, -vvv, which would evaluate to 1, 2, and 3, respectively\r\n            short: -v\r\n            allow_counting: True\r\n            var: verbosity\r\n        help:\r\n          message: |\r\n            Invoke the 'run' command \r\n          epilog: |\r\n            This line will be displayed at the end of the help text message\r\n          examples:\r\n            - example1: |\r\n                tasks $command\r\n            - example2: |\r\n                Usage example 2\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\nRunning `tasks run --help` should return the list of parameters along with the help message you defined.\r\n\r\n\u003ca name=\"populate-the-vars-block---embedded-shell-functions\"\u003e\u003c/a\u003e\r\n\r\n## Populate the vars block - embedded shell functions\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eAdd embedded shell functions: \u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    ### Global Options Block\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable \r\n    ### The commands block\r\n    commands:\r\n      run:\r\n        options:\r\n          foo:\r\n            help: \"This is some foo option\"\r\n            short: -f\r\n            long: --foo\r\n            type: choice\r\n            var: some_foo_variable\r\n            required: True\r\n            not_required_if: \r\n              - some_bar_variable\r\n            options:\r\n              - foo1\r\n              - foo2\r\n          bar:\r\n            help: \"This is some bar option\"\r\n            short: -b\r\n            long: --bar \r\n            type: str\r\n            var: some_bar_variable\r\n            required: False\r\n            required_if: \r\n              - hello\r\n              - some_baz_variable\r\n          baz:\r\n            help: \"This is some baz option\"\r\n            short: -z\r\n            long: --baz\r\n            type: str\r\n            var: some_baz_variable\r\n            required: False\r\n            mutually_exclusive_with: \r\n              - some_bar_variable\r\n              - some_foo_variable\r\n          envvar:\r\n            help: \"The value for this argument can be derived from an Environmental Variable\"\r\n            short: -E\r\n            long: --env-var\r\n            type: str\r\n            var: env_var\r\n            env_var: SOME_ENVIRONMENT_VARIABLE\r\n            env_var_show: True\r\n          num:\r\n            help: \"This is a numeric argument\"\r\n            short: -n\r\n            long: --number\r\n            var: some_num_variable\r\n            type: int\r\n            required: False \r\n            env_var_show: True\r\n          targets:\r\n            help: \"Playbook targets\"\r\n            short: -t\r\n            long: --targets\r\n            type: str\r\n            var: playbook_targets\r\n            required: True\r\n          multiple:\r\n            help: |-\r\n              This option can be specified multiple times\r\n            short: -m\r\n            long: --multiple\r\n            type: str\r\n            var: multiple_arg\r\n            allow_multiple: True\r\n          some_switch:\r\n            help: |-\r\n              This is some boolean option, behaves like Click's switches,\r\n              holds the value of True if specified\r\n              see: https://github.com/pallets/click\r\n            short: -s\r\n            long: --some-switch\r\n            is_flag: true\r\n            var: some_switch\r\n            required: True\r\n          say_hello:\r\n            help: \"Invoke the 'hello' embedded shell function\"\r\n            short: -hello\r\n            long: --say-hello\r\n            type: str\r\n            var: hello\r\n            is_flag: True\r\n          say_goodbye:\r\n            help: \"Invoke the 'goodbye' embedded shell function\"\r\n            short: -goodbye\r\n            long: --say-goodbye\r\n            type: str\r\n            var: goodbye\r\n            is_flag: True\r\n          hidden_option:\r\n            help: \"This is a hidden option\"\r\n            short: -O\r\n            long: --hidden-option\r\n            is_hidden: True\r\n            type: str\r\n            var: hidden\r\n            is_flag: True            \r\n          verbose:\r\n            help: |-\r\n              This is a sample paramter that supports counting, as with:\r\n              -v, -vv, -vvv, which would evaluate to 1, 2, and 3, respectively\r\n            short: -v\r\n            allow_counting: True\r\n            var: verbosity\r\n        ### The help message\r\n        help:\r\n          message: |\r\n            Invoke the 'run' command \r\n          epilog: |\r\n            This line will be displayed at the end of the help text message\r\n          examples:\r\n            - example1: |\r\n                tasks $command\r\n            - example2: |\r\n                Usage example 2\r\n        ### Embedded shell functions\r\n        functions:\r\n          hello:\r\n            shell: bash\r\n            help: Say hello\r\n            source: |-\r\n              echo Hello! The value for var1 is $var1\r\n          goodbye:\r\n            shell: bash\r\n            help: Say goodbye\r\n            source: |-\r\n              echo The value for var1 is $var1. Goodbye!\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n\u003ca name=\"embedded-shell-functions\"\u003e\u003c/a\u003e\r\n\r\nAgain, notice the two switches `-hello` and `-goodbye`, with mapped variables _hello_ and _goodbye_, respectively.\r\n\r\nThese mapped variables correspond to keys in the `functions` block with matching names.\r\n\r\nAs such, specifying either or both `-hello` and `-goodbye` in your `tasks run` invocation\u003cbr /\u003e\r\nwill short-circuit normal operation and execute the corresponding functions\u003cbr /\u003e \r\n**in the order in which you call them**.\r\n\r\nTry it yourself by running:\r\n\r\n- `tasks run -t local -s -b bar -m one -m two -vvv -O -hello -goodbye`\r\n- `tasks run -t local -s -b bar -m one -m two -vvv -O -goodbye -hello`\r\n\r\nThere is also a special flag `---invoke-function` that is globally available to all subcommands.\r\n\r\nInvocation is as follows: `tasks \u003csubcommand\u003e ---invoke-function \u003cfunction_name\u003e`.\r\n\r\nIn our example, we would run: `tasks run -t local -s -b bar -m one -m two -vvv -O ---invoke-function hello`\r\n\r\nFor more usage examples, see the [appendix](#usage-examples).\r\n\r\n\u003ca name=\"more-about-embedded-shell-functions\"\u003e\u003c/a\u003e\r\n\r\n### More about embedded shell functions\r\n\r\nLet's briefly side-step into embedded shell functions.\r\n\r\nThe syntax for nesting these under the _functions_ key is as follows:\r\n\r\n```\r\n          name_of_function:\r\n            shell: bash, ruby, or python\r\n            help: Help Text to Display\r\n            hidden: false/true\r\n            source: |-\r\n              {{ code }}\r\n```\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"bash-example\"\u003e\u003c/a\u003e\r\n\r\n#### Bash example:\r\n\r\n```\r\n          hello:\r\n            shell: bash\r\n            help: Hello World in Bash\r\n            hidden: false\r\n            source: |-\r\n              echo 'Hello World!'\r\n```\r\n\r\n\u003ca name=\"python-example\"\u003e\u003c/a\u003e\r\n\r\n#### Python example:\r\n\r\n```\r\n          hello:\r\n            shell: python\r\n            help: Hello World in Python\r\n            hidden: false\r\n            source: |-\r\n              print('Hello World!')\r\n```\r\n\r\n\u003ca name=\"ruby-example\"\u003e\u003c/a\u003e\r\n\r\n#### Ruby example:\r\n\r\n```\r\n          hello:\r\n            shell: ruby\r\n            help: Hello World in Ruby\r\n            hidden: false\r\n            source: |-\r\n              puts 'Hello World!'\r\n```\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"populate-the-vars-block---dynamic-inventory-expression\"\u003e\u003c/a\u003e\r\n\r\n## Populate the vars block - dynamic inventory expression\r\n\r\nA useful feature of this tool is the ability to define your ansible\u003cbr /\u003e\r\ninventory as a dynamic expression in the Taskfile itself.\r\n\r\nTo do so, we populate the with the _inventory_expression_ key.\r\n\r\nWhen the inventory is defined in this manner, the logic is as follows:\r\n\r\n- The inventory expression is evaluated\r\n- An ephemeral inventory file is created with the\u003cbr /\u003e\r\n  contents of this file being the output, or result, of that expression\r\n- The fully qualified path to the ephemeral inventory file is specified as the\u003cbr /\u003e\r\n  argument to the `ansible-playbook` inventory parameter `-i`\r\n\r\nLet's define our inventory expression:\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    ### Global Options Block\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable \r\n    ### The commands block\r\n    commands:\r\n      run:\r\n        options:\r\n          foo:\r\n            help: \"This is some foo option\"\r\n            short: -f\r\n            long: --foo\r\n            type: choice\r\n            var: some_foo_variable\r\n            required: True\r\n            not_required_if: \r\n              - some_bar_variable\r\n            options:\r\n              - foo1\r\n              - foo2\r\n          bar:\r\n            help: \"This is some bar option\"\r\n            short: -b\r\n            long: --bar \r\n            type: str\r\n            var: some_bar_variable\r\n            required: False\r\n            required_if: \r\n              - hello\r\n              - some_baz_variable\r\n          baz:\r\n            help: \"This is some baz option\"\r\n            short: -z\r\n            long: --baz\r\n            type: str\r\n            var: some_baz_variable\r\n            required: False\r\n            mutually_exclusive_with: \r\n              - some_bar_variable\r\n              - some_foo_variable\r\n          envvar:\r\n            help: \"The value for this argument can be derived from an Environmental Variable\"\r\n            short: -E\r\n            long: --env-var\r\n            type: str\r\n            var: env_var\r\n            env_var: SOME_ENVIRONMENT_VARIABLE\r\n            env_var_show: True\r\n          num:\r\n            help: \"This is a numeric argument\"\r\n            short: -n\r\n            long: --number\r\n            var: some_num_variable\r\n            type: int\r\n            required: False \r\n            env_var_show: True\r\n          targets:\r\n            help: \"Playbook targets\"\r\n            short: -t\r\n            long: --targets\r\n            type: str\r\n            var: playbook_targets\r\n            required: True\r\n          multiple:\r\n            help: |-\r\n              This option can be specified multiple times\r\n            short: -m\r\n            long: --multiple\r\n            type: str\r\n            var: multiple_arg\r\n            allow_multiple: True\r\n          some_switch:\r\n            help: |-\r\n              This is some boolean option, behaves like Click's switches,\r\n              holds the value of True if specified\r\n              see: https://github.com/pallets/click\r\n            short: -s\r\n            long: --some-switch\r\n            is_flag: true\r\n            var: some_switch\r\n            required: True\r\n          say_hello:\r\n            help: \"Invoke the 'hello' embedded shell function\"\r\n            short: -hello\r\n            long: --say-hello\r\n            type: str\r\n            var: hello\r\n            is_flag: True\r\n          say_goodbye:\r\n            help: \"Invoke the 'goodbye' embedded shell function\"\r\n            short: -goodbye\r\n            long: --say-goodbye\r\n            type: str\r\n            var: goodbye\r\n            is_flag: True\r\n          hidden_option:\r\n            help: \"This is a hidden option\"\r\n            short: -O\r\n            long: --hidden-option\r\n            is_hidden: True\r\n            type: str\r\n            var: hidden\r\n            is_flag: True            \r\n          verbose:\r\n            help: |-\r\n              This is a sample paramter that supports counting, as with:\r\n              -v, -vv, -vvv, which would evaluate to 1, 2, and 3, respectively\r\n            short: -v\r\n            allow_counting: True\r\n            var: verbosity\r\n        ### The help message\r\n        help:\r\n          message: |\r\n            Invoke the 'run' command \r\n          epilog: |\r\n            This line will be displayed at the end of the help text message\r\n          examples:\r\n            - example1: |\r\n                tasks $command\r\n            - example2: |\r\n                Usage example 2\r\n        ### Embedded shell functions\r\n        functions:\r\n          hello:\r\n            shell: bash\r\n            help: Say hello\r\n            source: |-\r\n              echo Hello! The value for var1 is $var1\r\n          goodbye:\r\n            shell: bash\r\n            help: Say goodbye\r\n            source: |-\r\n              echo The value for var1 is $var1. Goodbye!\r\n    ### The inventory expression              \r\n    inventory_expression: |\r\n      [local]\r\n      localhost ansible_connection=local\r\n      [web_hosts]\r\n      $(echo -e \"${webhosts}\" | tr ',' '\\n')\r\n      [db_hosts]\r\n      $(echo -e \"${dbhosts}\" | tr ',' '\\n')\r\n      [myhosts:children]\r\n      web_hosts\r\n      db_hosts\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\nAs you can see, the inventory expression is dynamic, as\u003cbr /\u003e\r\nit gets evaluated based on the output of inline shell commands.\r\n\r\nLet's focus on the variable _$webhosts_.\r\n\r\nAs per the logic described [above](#populate-the-vars-block---defaults), the variable $webhosts is a heredoc with a value of:\r\n\r\n```\r\nwebhosts='\r\nwebhost1\r\nwebhost2\r\nwebhost3\r\n'\r\n```\r\n\r\nAs such, the _web_hosts_ group in the inventory expression ...\r\n```\r\n      [web_hosts]\r\n      $(echo -e \"${webhosts}\" | tr ',' '\\n')\r\n```\r\n\r\n... will evaluate to:\r\n\r\n```\r\n[web_hosts]\r\nwebhost1\r\nwebhost2\r\nwebhost3\r\n```\r\n\r\nAlso, notice how the inline shell command transforms commas into newline characters by way of the transform (`tr`) command.\r\n\r\nThis makes it so that if we were to have defined the _webhosts_ variable\u003cbr /\u003e\r\nin the Tasksfile as `webhosts: webhost1,webhost2,webhost3`, it would have had the same outcome\u003cbr /\u003e\r\nas defining it as a list object in the _vars_ block.\r\n\r\n\u003ca name=\"populate-the-vars-block---inventory-file\"\u003e\u003c/a\u003e\r\n\r\n## Populate the vars block - inventory file\r\n\r\nWe can specify an inventory file instead of an inventory expression with the _inventory_file_ key.\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    ### Global Options Block\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable \r\n    ### The commands block\r\n    commands:\r\n      run:\r\n        options:\r\n          foo:\r\n            help: \"This is some foo option\"\r\n            short: -f\r\n            long: --foo\r\n            type: choice\r\n            var: some_foo_variable\r\n            required: True\r\n            not_required_if: \r\n              - some_bar_variable\r\n            options:\r\n              - foo1\r\n              - foo2\r\n          bar:\r\n            help: \"This is some bar option\"\r\n            short: -b\r\n            long: --bar \r\n            type: str\r\n            var: some_bar_variable\r\n            required: False\r\n            required_if: \r\n              - hello\r\n              - some_baz_variable\r\n          baz:\r\n            help: \"This is some baz option\"\r\n            short: -z\r\n            long: --baz\r\n            type: str\r\n            var: some_baz_variable\r\n            required: False\r\n            mutually_exclusive_with: \r\n              - some_bar_variable\r\n              - some_foo_variable\r\n          envvar:\r\n            help: \"The value for this argument can be derived from an Environmental Variable\"\r\n            short: -E\r\n            long: --env-var\r\n            type: str\r\n            var: env_var\r\n            env_var: SOME_ENVIRONMENT_VARIABLE\r\n            env_var_show: True\r\n          num:\r\n            help: \"This is a numeric argument\"\r\n            short: -n\r\n            long: --number\r\n            var: some_num_variable\r\n            type: int\r\n            required: False \r\n            env_var_show: True\r\n          targets:\r\n            help: \"Playbook targets\"\r\n            short: -t\r\n            long: --targets\r\n            type: str\r\n            var: playbook_targets\r\n            required: True\r\n          multiple:\r\n            help: |-\r\n              This option can be specified multiple times\r\n            short: -m\r\n            long: --multiple\r\n            type: str\r\n            var: multiple_arg\r\n            allow_multiple: True\r\n          some_switch:\r\n            help: |-\r\n              This is some boolean option, behaves like Click's switches,\r\n              holds the value of True if specified\r\n              see: https://github.com/pallets/click\r\n            short: -s\r\n            long: --some-switch\r\n            is_flag: true\r\n            var: some_switch\r\n            required: True\r\n          say_hello:\r\n            help: \"Invoke the 'hello' embedded shell function\"\r\n            short: -hello\r\n            long: --say-hello\r\n            type: str\r\n            var: hello\r\n            is_flag: True\r\n          say_goodbye:\r\n            help: \"Invoke the 'goodbye' embedded shell function\"\r\n            short: -goodbye\r\n            long: --say-goodbye\r\n            type: str\r\n            var: goodbye\r\n            is_flag: True\r\n          hidden_option:\r\n            help: \"This is a hidden option\"\r\n            short: -O\r\n            long: --hidden-option\r\n            is_hidden: True\r\n            type: str\r\n            var: hidden\r\n            is_flag: True            \r\n          verbose:\r\n            help: |-\r\n              This is a sample paramter that supports counting, as with:\r\n              -v, -vv, -vvv, which would evaluate to 1, 2, and 3, respectively\r\n            short: -v\r\n            allow_counting: True\r\n            var: verbosity\r\n        ### The help message\r\n        help:\r\n          message: |\r\n            Invoke the 'run' command \r\n          epilog: |\r\n            This line will be displayed at the end of the help text message\r\n          examples:\r\n            - example1: |\r\n                tasks $command\r\n            - example2: |\r\n                Usage example 2\r\n        ### Embedded shell functions\r\n        functions:\r\n          hello:\r\n            shell: bash\r\n            help: Say hello\r\n            source: |-\r\n              echo Hello! The value for var1 is $var1\r\n          goodbye:\r\n            shell: bash\r\n            help: Say goodbye\r\n            source: |-\r\n              echo The value for var1 is $var1. Goodbye!\r\n    ### Inventory file\r\n    inventory_file: '/some/path/some/inventory.yaml'\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n**Notes of Importance**:\r\n\r\n- The value you provide to the _inventory_file_ key supports templating\r\n    - That is, any of the variables available runtime variables can be used, for example:\r\n        - `inventory_file: '/some/path/some/inventory_$foo_variable.yaml'`\r\n        - `inventory_file: '/some/path/some/inventory_$var1.yaml'`\r\n- You should not be specifying both an _inventory_file_ and an _inventory_expression_, as you get unexpected results.\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"add-tasks\"\u003e\u003c/a\u003e\r\n\r\n## Add tasks\r\n\r\nFinally, let's add some proper ansible tasks!\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eClick to Expand\u003c/summary\u003e\r\n\r\n*Taskfile.yaml*\r\n\r\n```\r\n### The hosts block\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  ### The vars block  \r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    var4: |-\r\n      This is a multi-line value\r\n      of type string\r\n    var5:\r\n      - listvalue1\r\n      - listvalue2\r\n      - listvalue3\r\n      - listvalue4\r\n    var6:\r\n      some_key:\r\n        some_child_key: dictvalue1\r\n    var7: $(echo some_value)\r\n    var8: 8000\r\n    dbhosts:\r\n      - dbhost1\r\n      - dbhost2\r\n      - dbhost3\r\n    webhosts:\r\n      - webhost1\r\n      - webhost2\r\n      - webhost3\r\n    ### Global Options Block\r\n    globals:\r\n      options:\r\n          my_global_option:\r\n            help: \"This is my global option\"\r\n            short: -g\r\n            long: --global\r\n            var: some_global_variable \r\n    ### The commands block\r\n    commands:\r\n      run:\r\n        options:\r\n          foo:\r\n            help: \"This is some foo option\"\r\n            short: -f\r\n            long: --foo\r\n            type: choice\r\n            var: some_foo_variable\r\n            required: True\r\n            not_required_if: \r\n              - some_bar_variable\r\n            options:\r\n              - foo1\r\n              - foo2\r\n          bar:\r\n            help: \"This is some bar option\"\r\n            short: -b\r\n            long: --bar \r\n            type: str\r\n            var: some_bar_variable\r\n            required: False\r\n            required_if: \r\n              - hello\r\n              - some_baz_variable\r\n          baz:\r\n            help: \"This is some baz option\"\r\n            short: -z\r\n            long: --baz\r\n            type: str\r\n            var: some_baz_variable\r\n            required: False\r\n            mutually_exclusive_with: \r\n              - some_bar_variable\r\n              - some_foo_variable\r\n          envvar:\r\n            help: \"The value for this argument can be derived from an Environmental Variable\"\r\n            short: -E\r\n            long: --env-var\r\n            type: str\r\n            var: env_var\r\n            env_var: SOME_ENVIRONMENT_VARIABLE\r\n            env_var_show: True\r\n          num:\r\n            help: \"This is a numeric argument\"\r\n            short: -n\r\n            long: --number\r\n            var: some_num_variable\r\n            type: int\r\n            required: False \r\n            env_var_show: True\r\n          targets:\r\n            help: \"Playbook targets\"\r\n            short: -t\r\n            long: --targets\r\n            type: str\r\n            var: playbook_targets\r\n            required: True\r\n          multiple:\r\n            help: |-\r\n              This option can be specified multiple times\r\n            short: -m\r\n            long: --multiple\r\n            type: str\r\n            var: multiple_arg\r\n            allow_multiple: True\r\n          some_switch:\r\n            help: |-\r\n              This is some boolean option, behaves like Click's switches,\r\n              holds the value of True if specified\r\n              see: https://github.com/pallets/click\r\n            short: -s\r\n            long: --some-switch\r\n            is_flag: true\r\n            var: some_switch\r\n            required: True\r\n          say_hello:\r\n            help: \"Invoke the 'hello' embedded shell function\"\r\n            short: -hello\r\n            long: --say-hello\r\n            type: str\r\n            var: hello\r\n            is_flag: True\r\n          say_goodbye:\r\n            help: \"Invoke the 'goodbye' embedded shell function\"\r\n            short: -goodbye\r\n            long: --say-goodbye\r\n            type: str\r\n            var: goodbye\r\n            is_flag: True\r\n          hidden_option:\r\n            help: \"This is a hidden option\"\r\n            short: -O\r\n            long: --hidden-option\r\n            is_hidden: True\r\n            type: str\r\n            var: hidden\r\n            is_flag: True            \r\n          verbose:\r\n            help: |-\r\n              This is a sample paramter that supports counting, as with:\r\n              -v, -vv, -vvv, which would evaluate to 1, 2, and 3, respectively\r\n            short: -v\r\n            allow_counting: True\r\n            var: verbosity\r\n        ### The help message\r\n        help:\r\n          message: |\r\n            Invoke the 'run' command \r\n          epilog: |\r\n            This line will be displayed at the end of the help text message\r\n          examples:\r\n            - example1: |\r\n                tasks $command\r\n            - example2: |\r\n                Usage example 2\r\n        ### Embedded shell functions\r\n        functions:\r\n          hello:\r\n            shell: bash\r\n            help: Say hello\r\n            source: |-\r\n              echo Hello! The value for var1 is $var1\r\n          goodbye:\r\n            shell: bash\r\n            help: Say goodbye\r\n            source: |-\r\n              echo The value for var1 is $var1. Goodbye!\r\n    ### The inventory expression\r\n    inventory_expression: |\r\n      [local]\r\n      localhost ansible_connection=local\r\n      [web_hosts]\r\n      $(echo -e \"${webhosts}\" | tr ',' '\\n')\r\n      [db_hosts]\r\n      $(echo -e \"${dbhosts}\" | tr ',' '\\n')\r\n      [myhosts:children]\r\n      web_hosts\r\n      db_hosts            \r\n  tasks:\r\n    - name: Show Variables\r\n      debug:\r\n        msg: |-\r\n          {{ hostvars[inventory_hostname] | to_nice_json }}\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n\u003cbr /\u003e\r\nThe task above will display all available host variables.\r\n\r\n\u003ca name=\"usage-examples\"\u003e\u003c/a\u003e\r\n\r\n# Usage Examples\r\n\r\nQuick usage examples:\r\n\r\n* Display help for main command\u003cbr /\u003e\r\n  `tasks --help`\r\n* Display help for the *run* subcommand\u003cbr /\u003e\r\n  `tasks run --help`\r\n* Initialize your workspace\u003cbr /\u003e\r\n  `tasks init`\u003cbr /\u003e\r\n* Run the Taskfile.yaml playbook, passing in additional options to the underlying subprocess\u003cbr /\u003e\r\n  `tasks run -t local -s -b bar -m one -m two`\u003c/br\u003e\r\n* Don't do anything, just echo the underlying shell command\u003cbr /\u003e\r\n  `tasks run -t local -s -b bar -m one -m two -O ---echo`\u003cbr /\u003e\r\n  Result should be similar to:\u003cbr /\u003e\r\n  `ansible-playbook -i /var/folders/5f/4g4xnnv958q52108qxd2rj_r0000gn/T/ansible-inventorytlmz2hpz.tmp.ini \\\r\n  -e \"{'var1':'${var1}'}\" ... Taskfile.yaml`\r\n* Run the embedded function `hello`\u003cbr /\u003e\r\n  `tasks run -t local -s -b bar -m one -m two -hello`\r\n* Run the embedded functions `hello` and `goodbye`\u003cbr /\u003e\r\n  `run -t local -s -b bar -m one -m two -hello -goodbye`\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\r\n\r\n# Installation\r\n\r\nAnsible-taskrunner consists of the `tasks` command.\r\n\r\nIt can be installed in a few ways:\r\n\r\n1. pip install ansible-taskrunner\r\n2. pip install git+https://github.com/berttejeda/ansible-taskrunner.git\r\n3. Obtaining a [release](#single-executable-releases) (these lag behind the pip distributions)\r\n\r\nNote: You'll need to pre-install a python distribution for the Windows MSI release.\r\nNot yet sure if I am doing something wrong or if that's by design.\r\nI lean toward the former :|\r\n\r\n\u003ca name=\"more-examples\"\u003e\u003c/a\u003e\r\n\r\n## More Examples\r\n\r\nReview the [examples](examples) directory for more hands-on usage samples.\r\n\r\n\u003ca name=\"appendix\"\u003e\u003c/a\u003e\r\n\r\n# Appendix\r\n\r\n\r\n\u003ca name=\"the-options-separator\"\u003e\u003c/a\u003e\r\n## The Options Separator\r\n\r\nWhen you pass the `---` options separator to any subcommand, anything\r\nafter the separator is passed directly to the ansible subprocess.\r\n\r\n\u003ca name=\"bastion-mode\"\u003e\u003c/a\u003e\r\n## Bastion Mode\r\n\r\nIf you're launching the `tasks` command from a Windows host, this tool will automatically execute in _Bastion Mode_\r\n\r\nUnder Bastion Mode, the `tasks` command will:\r\n- Execute the `ansible-playbook` subprocess via a _bastion host_, i.e. a remote machine that _should have_ `ansible` installed\r\n- This is done via ssh using the [paramiko](http://www.paramiko.org/) module\r\n\r\nRunning in Bastion Mode requires a configuration file containing the ssh connection settings.\r\n\r\nTo initialize this configuration file, you can simply run `tasks init`.\r\n\r\nFor full usage options, enter in `tasks init --help`.\r\n\r\nOnce you've initialized the configuration file, you should see *sftp-config.json* in your workspace.\r\n\r\nThis configuration file is fashioned after the [sftp](https://packagecontrol.io/packages/SFTP)\u003cbr /\u003e\r\nplugin for [Sublime Text](https://www.sublimetext.com/) and is thus compatible.\r\n\r\n\u003ca name=\"special-variables\"\u003e\u003c/a\u003e\r\n\r\n## Special Variables\r\n\r\n\u003ca name=\"ansible_playbook_command\"\u003e\u003c/a\u003e\r\n\r\n### ansible_playbook_command\r\n\r\nIf you define the playbook variable *ansible_playbook_command*, this will override the underlying ansible-playbook command invocation.\r\n\r\nAs an example, suppose I define this variable in the above *Taskfile.yaml*, as follows:\r\n\r\n```\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  vars:\r\n    ansible_playbook_command: 'python ${HOME}/ansible_2.7.8/ansible-playbook'\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    # ...\r\n```\r\nUpon invoking the `tasks` command with the `---echo` flag:\r\n\r\n- The temporary inventory would be revealed as:\u003cbr /\u003e\r\n\r\n```\r\ninventory_is_ephemeral=True\r\nif [[ \"$inventory_is_ephemeral\" == \"True\" ]];then\r\necho -e \"\"\"${inventory_expression}\"\"\"| while read line;do\r\n eval \"echo -e ${line}\" \u003e\u003e \"/var/folders/some/path/ansible-inventoryo4fw4ttc.tmp.ini\";\r\ndone\r\nfi;\r\n```\r\n\r\n\\*_The above inventory file path will differ, of course_\r\n\r\n- And the underlying shell command would be revealed as:\u003cbr /\u003e\r\n\r\n```\r\npython ${HOME}/ansible_2.7.8/ansible-playbook \\\r\n-i /var/folders/some/path/ansible-inventoryo4fw4ttc.tmp.ini \\\r\n-e \"{'var1':'${var1}'}\" \\\r\n-e \"{'var2':'${var2}'}\" \\\r\n-e \"{'var3':'${var3}'}\" \\\r\n... Taskfile.yaml\r\n```\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"pre_execution\"\u003e\u003c/a\u003e\r\n\r\n### pre_execution\r\n\r\nAnything defined under the *pre_execution* variable will be evaluated\r\n**before** all other statements in the underlying shell expression.\r\n\r\nAs an example, suppose I define the pre_execution variable in the above *Taskfile.yaml*, as follows:\r\n\r\n```\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  vars:\r\n    pre_execution: |-\r\n      export pxe_var=some_value\r\n      touch /tmp/.run.lock\r\n```\r\n\r\nUpon invoking the `tasks` command with the `---echo` flag:\r\n\r\n- The underlying shell expression would be revealed as:\u003cbr /\u003e\r\n\r\n```\r\n...\r\nexport pxe_var=some_value\r\ntouch /tmp/.run.lock\r\n...\r\n```\r\n\r\nThe commands above are always placed **before**\u003cbr /\u003e\r\nall variables declarations in the underlying shell expresison.\r\n\r\n\u003ca name=\"post_execution\"\u003e\u003c/a\u003e\r\n\r\n### post_execution\r\n\r\nThis is similar to *pre_execution*, except that anything defined under the *post_execution* variable will be evaluated\r\n**after** all other statements in the underlying shell expression.\r\n\r\n\u003ca name=\"environment_vars\"\u003e\u003c/a\u003e\r\n\r\n### environment_vars\r\n\r\nBy defining the playbook dictionary variable *environment_vars*,\u003cbr /\u003e\r\nthe following occurs:\r\n\r\n- For each dictionary `key: value` pair:\r\n    - A corresponding `export` statement is defined in the underlying shell expression\r\n\r\nAs an example, suppose I define this variable in the above *Taskfile.yaml*, as follows:\r\n\r\n```\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  vars:\r\n    ansible_playbook_command: 'python ${HOME}/ansible_2.7.8/ansible-playbook'\r\n    var1: value1\r\n    var2: value2\r\n    var3: value3\r\n    some_path: /some/path\r\n    environment_vars:\r\n      MY_ENV_VAR1: \"${some_path}/${var1}\"    \r\n      MY_ENV_VAR2: \"${some_path}/${var2}\"    \r\n    # ...\r\n```\r\n\r\nUpon invoking the `tasks` command with the `---echo` flag:\r\n\r\n- The underlying shell expression would be revealed as:\u003cbr /\u003e\r\n\r\n```\r\nvar1=\"value1\"\r\nvar2=\"value2\"\r\nexport MY_ENV_VAR1=\"${some_path}/${var1}\"\r\nexport MY_ENV_VAR2=\"${some_path}/${var2}\"\r\n```\r\n\r\nThese export statements are always placed **after**\u003cbr /\u003e\r\nall variables declarations in the underlying shell expresison.\r\n\r\n#### ANSIBLE_ Variables\r\n\r\nAny variables matching ANSIBLE_.* will automatically be expressed as export statements.\r\n\r\nAs an example, suppose I define such variables in the above *Taskfile.yaml*, as follows:\r\n\r\n```\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  vars:\r\n    var1: value1\r\n    var2: value2\r\n    ANSIBLE_VAULT_PASSWORD_FILE: /some/path/some/password_file\r\n    ANSIBLE_CALLBACK_PLUGINS: /some/other/path/some/plugins\r\n    # ...\r\n```\r\n\r\nUpon invoking the `tasks` command with the `---echo` flag:\r\n\r\n- The underlying shell expression would be revealed as:\u003cbr /\u003e\r\n\r\n```\r\nvar1=\"value1\"\r\nvar2=\"value2\"\r\nexport ANSIBLE_VAULT_PASSWORD_FILE=\"/some/path/some/password_file\"\r\nexport ANSIBLE_CALLBACK_PLUGINS=\"/some/other/path/some/plugins\"\r\n```\r\n\r\n\u003ca name=\"cli_provider\"\u003e\u003c/a\u003e\r\n\r\n### cli_provider\r\n\r\nYou can override the underlying command-line provider in two ways:\r\n\r\n- Via the tasks config file (see [examples](#examples))\r\n- By defining the variable *cli_provider* in the specified Taskfile\r\n\r\nAs an example, suppose I define this variable in the above *Taskfile.yaml*, as follows:\r\n\r\n```\r\n- hosts: myhosts\r\n  gather_facts: true\r\n  become: true\r\n  vars:\r\n    cli_provider: bash\r\n    # ...\r\n```\r\n\r\nUpon invoking the `tasks` command, you will note that the app no longer operates in an **ansible-playbook** mode, but rather as yaml-abstracted bash-script.\r\n\r\nThere are three cli-providers built in to the tasks command:\r\n\r\n- ansible\r\n- bash\r\n- vagrant\r\n\r\n\u003ca name=\"__ansible_run_flags__\"\u003e\u003c/a\u003e\r\n\r\n### __ansible_run_flags__\r\n\r\nApart from utilizing the `---` options separator, you can specify additional options to pass to the underlying `ansible-playbook` subprocess by setting an appropriate value for **\\_\\_ansible_run_flags\\_\\_** \r\nvia Environmental variable or Taskfile, as with:\r\n\r\n`__ansible_run_flags__: --diff`\r\n\r\nor \r\n\r\n`export __ansible_run_flags__='--diff'`\r\n\r\n\u003ca name=\"__tasks_file__\"\u003e\u003c/a\u003e\r\n\r\n### __tasks_file__\r\n\r\nThe **\\_\\_tasks_file\\_\\_** variable points to the current Taskfile.\r\n\r\nIt is available to the underlying subprocess shell.\r\n\r\n### __command__\r\n\r\nThe **\\_\\_command\\_\\_** variable points to the name of the invoked subcommand.\r\n\r\nIt is available to the underlying subprocess shell.\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"advanced-options\"\u003e\u003c/a\u003e\r\n\r\n## Mutually Exclusive Options\r\n\r\nThis tool supports the following advanced options:\r\n\r\n  - Mutually Exclusive, see [Mutually exclusive option groups in python Click - Stack Overflow](https://stackoverflow.com/questions/37310718/mutually-exclusive-option-groups-in-python-click).\r\n  - Mutually Inclusive\r\n  - Conditionally required\r\n\r\nSuppose you want a set of options such that:\r\n- You want to accept one option but only if another, related option has not been specified\r\n\r\nYou can accomplish this by defining your option with the following parameters:\r\n\r\n```\r\n  - required: False\r\n  - mutually_exclusive_with: \r\n    - some_bar_variable\r\n    - some_foo_variable\r\n```\r\n\r\nIn the above configuration, calling this option along with options\u003cbr /\u003e \r\n`-f|-foo` and `-b|-bar` will trigger an illegal usage error, since you've\u003cbr /\u003e\r\nmarked the option as mutually exclusive with either of these two options.\r\n\r\nFeel free to review the [Taskfile.yaml](Taskfile.yaml), as you'll find an example of:\r\n\r\n- mutually exclusive\r\n- mutually inclusive\r\n- conditionally required\r\n\r\n\u003ca name=\"cloned-subcommands\"\u003e\u003c/a\u003e\r\n\r\n## Cloned subcommands\r\n\r\nThere might exist edge cases in which you need two different\r\nsubcommands to be defined with identical commandline options.\r\n\r\nThis could be useful for, say, subcommands like `install` or `uninstall`,\r\nwhere the only differentiating factor between the two would be the\r\nname of the subcommand being invoked.\r\n\r\nTo enable this, simply declare your subcommand with a pipe `|` delimiter, as with:\r\n\r\n```\r\n    commands:\r\n      install|uninstall:\r\n        options:\r\n          foo:\r\n            help: \"Install/Uninstall an app\"\r\n            short: -n\r\n            long: --app-name\r\n            type: choice\r\n            var: app_name\r\n            required: True\r\n```\r\n\r\n\u003ca name=\"simple-templating\"\u003e\u003c/a\u003e\r\n\r\n## Simple Templating\r\n\r\nAs of version 1.1.5, simple templating is available to the following objects:\r\n\r\n- Help messages\r\n- Examples\r\n- Options\r\n- Options values\r\n\r\nWhat this means is that we expose a limited set of internal variables to the above.\r\n\r\nAs an example:\r\n\r\n```\r\n        help:\r\n          message: |\r\n            Invoke the 'run' command \r\n          epilog: |\r\n            This line will be displayed at the end of the help text message\r\n          examples:\r\n            - example1: |\r\n                tasks -f $tf_path --foo foo --bar bar\r\n            - example2: |\r\n                tasks -f $tf_path --foo foo --baz baz\r\n```            \r\n\r\nIn the above strings, `$tf_path` will expand to the internal variable tf_path,\r\nwhich holds the relative path to the current tasks file.\r\n\r\nBelow is a list of available variables for your convenience:\r\n\r\n```\r\nVariable        | Description\r\n-------------   | -------------\r\n__command__     | The name of the current subcommand\r\ncli_args        | The current command-line invocation\r\ncli_args_short  | The current command-line invocation, minus the executable\r\nsys_platform    | The OS Platform as detected by Python\r\ntf_path         | The relative path to the specified Taskfile\r\n```\r\n\r\nAdditionally, all **currently set environmental variables** are available for templating.\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"single-executable-releases\"\u003e\u003c/a\u003e\r\n\r\n## Single-Executable Releases\r\n\r\nThis script also ships as a zipapp executable (similar to a windows .exe).\r\n\r\nHead over to the [releases page](https://github.com/berttejeda/ansible-taskrunner/releases) for release downloads.\r\n\r\nYou can also build your own single-executable zipapp, as follows:\r\n\r\n1. Make sure you have the [make-zipapp](https://github.com/berttejeda/make-zipapp) executable in your path\r\n1. Invoking build tasks\r\n  - Build zipapp: `python ansible_taskrunner/cli.py -f Makefile.yaml run ---make zipapp`\r\n\r\nRead More on zipapps: [zipapp — Manage executable Python zip archives — Python 3.7.4rc2 documentation](https://docs.python.org/3/library/zipapp.html)\r\n\r\n\u003ca name=\"unit-testing\"\u003e\u003c/a\u003e\r\n\r\n## Unit Testing\r\n\r\nTo run all tests, simply call the test script, as with:\r\n\r\n`python tests/test_ansible_taskrunner.py`\r\n\r\n# TODO - Add more tests!\r\n\r\n[Back To Top](#top)\r\n\u003ca name=\"license-and-credits\"\u003e\u003c/a\u003e\r\n\r\n# License and Credits\r\n\r\nThis project adopts the the MIT distribution License.\r\n\r\n[Releases](https://github.com/berttejeda/ansible-taskrunner/releases) come bundled with the following opensource python packages:\r\n\r\n- [click](https://github.com/pallets/click), licensed under BSD-3-Clause\r\n- [pyYaml](https://github.com/yaml/pyyaml), licensed under MIT\r\n\r\nLastly, this package was created with Cookiecutter and the `audreyr/cookiecutter-pypackage` project template.\r\n\r\n- Cookiecutter: https://github.com/audreyr/cookiecutter\r\n- audreyr/cookiecutter-pypackage: https://github.com/audreyr/cookiecutter-pypackage\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fberttejeda%2Fansible-taskrunner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fberttejeda%2Fansible-taskrunner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fberttejeda%2Fansible-taskrunner/lists"}