> For the complete documentation index, see [llms.txt](https://imarslo.gitbook.io/handbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://imarslo.gitbook.io/handbook/awesomeshell/ansible.md).

# ansible

* [environment](#environment)
  * [install](#install)
  * [upgrade](#upgrade)
  * [completion](#completion)
* [ansible-vault](#ansible-vault)
  * [encrypted files](#encrypted-files)
  * [prompt for the password](#prompt-for-the-password)
  * [reset key](#reset-key)
  * [encrypt](#encrypt)
  * [decrypt](#decrypt)
  * [view](#view)
* [ansible-galaxy](#ansible-galaxy)
* [ansible-playbook](#ansible-playbook)
  * [tags](#tags)
* [vault CLI](#vault-cli)
  * [environment variables](#environment-variables)
  * [kv get](#kv-get)
  * [kv list](#kv-list)
* [ansible-config](#ansible-config)
  * [get all default](#get-all-default)
* [ansible-lint](#ansible-lint)
* [ansible-tools](#ansible-tools)
* [plugin](#plugin)
  * [lookup](#lookup)
  * [Become](#become)
* [troubleshooting](#troubleshooting)

> \[!NOTE|label:references:]
>
> * [Ansible中文权威指南](http://www.ansible.com.cn/index.html)
>   * [Vault](http://www.ansible.com.cn/docs/playbooks_vault.html)
>   * [Playbooks](http://www.ansible.com.cn/docs/playbooks.html)
> * [Ansible Documentation](https://docs.ansible.com/ansible/latest/index.html)
>   * [Installing Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)
>   * [Tips and tricks](https://docs.ansible.com/ansible/3/user_guide/playbooks_best_practices.html#tip-for-variables-and-vaults)
>   * [ansible.builtin.template](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html)
> * [Sample Ansible setup](https://docs.ansible.com/ansible/latest/tips_tricks/sample_setup.html)
> * [How to build your inventory](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html)
> * [\* Filters](https://docs.ansible.com/ansible/2.9/user_guide/playbooks_filters.html#filters)
> * [用 Ansible 实现网络自动化](https://linux.cn/article-9964-1.html)

### environment

```bash
$ sudo dnf install wget yum-utils make gcc openssl-devel bzip2-devel libffi-devel zlib-devel
$ sudo dnf groupinstall 'development tools
$ sudo dnf -y install epel-release
$ sudo dnf install python39
$ sudo update-alternatives --config python
$ sudo update-alternatives --config python3
```

#### install

```bash
$ python -m pip install --user ansible

# or via pipx
$ python3 -m pip install pipx
$ pipx ensurepath
$ pipx install ansible --include-deps
```

* install for development

  ```bash
  $ python -m pip install --user https://github.com/ansible/ansible/archive/devel.tar.gz
  ```

#### upgrade

```bash
$ python -m pip install --user --upgrade ansible

# with pipx
$ pipx upgrade --include-injected ansible
```

#### [completion](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#adding-ansible-command-shell-completion)

```bash
$ python -m pip install --user argcomplete
$ cat >> ~/.bashrc << EOF
  command -v ansible > /dev/null && eval $(register-python-argcomplete ansible)           &&
                                    eval $(register-python-argcomplete ansible-config)    &&
                                    eval $(register-python-argcomplete ansible-console)   &&
                                    eval $(register-python-argcomplete ansible-doc)       &&
                                    eval $(register-python-argcomplete ansible-galaxy)    &&
                                    eval $(register-python-argcomplete ansible-inventory) &&
                                    eval $(register-python-argcomplete ansible-playbook)  &&
                                    eval $(register-python-argcomplete ansible-pull)      &&
                                    eval $(register-python-argcomplete ansible-vault)
EOF
```

* [completion.bash](https://github.com/dysosmus/ansible-completion)

  ```bash
  $ mkdir -p ~/.marslo/.completion
  # older version
  $ git clone git@github.com:dysosmus/ansible-completion.git ~/.marslo/.completion/ansible-completion

  # new version
  $ git clone git@github.com:marslo/ansible-completion.git   ~/.marslo/.completion/ansible-completion

  $ cat >> ~/.bashrc << EOF
  [ -d '~/.marslo/.completion/ansible-completion' ] && eval $(cat ~/.marslo/.completion/ansible-completion/*.bash)
  EOF
  ```

  * or via `ln`

    ```bash
    $ ls -1 --color=none /path/to/ansible-completion/*.bash |
         xargs -t -I{} bash -c "ln -svf {} /usr/local/share/bash-completion/completions/\$(basename {} | awk -F'.' '{print \$1}')"
    ```

### ansible-vault

> \[!NOTE]
>
> * [\* iMarslo : check line ending](https://github.com/marslo/ibook/blob/marslo/docs/cheatsheet/text-processing/text-processing.html#check-line-ending)
> * [\* iMarslo : remove the ending '\n'](https://github.com/marslo/ibook/blob/marslo/docs/cheatsheet/text-processing/text-processing.html#remove-the-ending-\n)
> * [Ansible Documentation](https://docs.ansible.com/ansible/latest/index.html)
>   * [\* Ansible Vault](https://docs.ansible.com/ansible/2.8/user_guide/vault.html)
>   * [Protecting sensitive data with Ansible vault](https://docs.ansible.com/ansible/latest/vault_guide/index.html)
>   * [Encrypting content with Ansible Vault](https://docs.ansible.com/ansible/3/user_guide/vault.html)
>   * [Using Vault in playbooks](https://docs.ansible.com/ansible/2.8/user_guide/playbooks_vault.html)
>   * [Managing vault passwords](https://docs.ansible.com/ansible/latest/vault_guide/vault_managing_passwords.html)
>   * [Community.Hashi\_Vault](https://docs.ansible.com/ansible/latest/collections/community/hashi_vault/index.html)
>   * [community.hashi\_vault.hashi\_vault lookup - Retrieve secrets from HashiCorp’s Vault](https://docs.ansible.com/ansible/latest/collections/community/hashi_vault/hashi_vault_lookup.html)
> * [10 ansible vault examples to decrypt/encrypt string & files](https://www.golinuxcloud.com/ansible-vault-example-encrypt-string-playbook/)
> * [Ansible 详解（四）：Ansible-vault](https://zhuanlan.zhihu.com/p/39158667)
> * [Ansible: How to pass multiple password files to playbook](https://stackoverflow.com/a/65684902/2940319)

#### [encrypted files](https://docs.ansible.com/ansible/3/user_guide/vault.html#creating-encrypted-files)

> \[!NOTE|label:references:]
>
> * [Why should text files end with a newline?](https://stackoverflow.com/q/729692/2940319)
> * [Removing a newline character at the end of a file](https://stackoverflow.com/a/27274234/2940319)
>
>   ```bash
>   $ truncate -s -1 /path/to/yaml
>   ```
> * [sed solution](https://stackoverflow.com/a/63777386/2940319)
>
>   ```bash
>   $ sed -z s/.$// pw.txt | od -c
>   0000000   a   b   c
>   0000003
>   ```
> * [printf solution](https://stackoverflow.com/a/12148703/2940319)
>
>   ```bash
>   $ printf %s "$(< pw.txt)" | od -c
>   0000000   a   b   c
>   0000003
>   ```
> * [head solution](https://stackoverflow.com/a/12579554/2940319)
>
>   ```bash
>   $ head -c -1 pw.txt | od -c
>   0000000   a   b   c  \n   e   f   g
>   0000007
>   ```

```bash
$ truncate -s -1 foo.yml

## encrypt file
$ ansible-vault encrypt --vault-id @prompt foo.yml
New vault password (default):
Confirm new vault password (default):

## create new file
$ ansible-vault create --vault-id @prompt foo.yml
New vault password (default):
Confirm new vault password (default):

$ cat foo.yml
$ANSIBLE_VAULT;1.1;AES256
65393763393937353538636266646432646265643531343530623436373462633663333234653032
6131396532663939376339306261616637316561343531350a393536353331343837653265383037
30343839316531666530336134623135313535336136653232653533643131303364306265393336
3234366662313332640a613963633766663061643064356530643863373138393039326466333638
3638
```

* create with name

  ```bash
  $ ansible-vault create --vault-id test@prompt foo.yml
  New vault password (test):
  Confirm new vault password (test):

  $ cat foo.yml
  $ANSIBLE_VAULT;1.2;AES256;test
  33303164313336626433376532306266633237333038653931386531616637666637626238346339
  3764383262343066636236626666613562363130636565630a313966376138323931333635333266
  32633330356132626637663534633165356133653639653130303839336338336261316362343065
  3964613438623337630a663735313836353566326333323732303232303864393063646432353463
  3631
  ```

#### [prompt for the password](https://docs.ansible.com/ansible/3/user_guide/vault.html#using-vault-id-without-a-vault-id)

> \[!TIP] via `--vault-id @prompt`
>
> \
> \- \[How to see special characters?]\(<https://www.unix.com/unix-for-dummies-questions-and-answers/151193-how-see-special-characters.html>) - be aware of the \`echo\` will automatically appending the \`\n\` in the end of the line: \`\`\`bash $ echo 'abc' | od -c 0000000 a b c \n 0000004 \`\`\` - with \`echo -n\` \`\`\`bash $ echo -n 'abc' | od -c 0000000 a b c 0000003 \`\`\`

```bash
$ echo -n 'Test123!' | ansible-vault encrypt_string --vault-id @prompt
New vault password (default):
Confirm new vault password (default):
Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)

Encryption successful
!vault |
          $ANSIBLE_VAULT;1.1;AES256
          62306630653236616438653236353135623936626332636337396432346235376364386233363938
          3930663634396138373139643031396433386339353634640a323938323431356330323363353335
          61636134636539326539623665393261643462396239653864313861393761633762313161386464
          3166333136366465370a323765386238646539613438333334633434613533373565326464383836
          6464
```

* or

  ```bash
  $ ansible-vault encrypt_string
  New Vault password:
  Confirm New Vault password:
  Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)
  abc^D                          # ctrl-d twice
  Encryption successful
  !vault |
            $ANSIBLE_VAULT;1.1;AES256
            39323234633365393633306135386362373463356636633937336236643763616232383832396333
            3136343265346534306638343738363435393964353262330a313331323161653832656365336331
            36356564653565613664666631346434306366666163393463633030363732336436346364613638
            3038303934366166320a633064326333623062663362343031633065333138313762353534643530
            633
  ```

#### reset key

```bash
$ ansible-vault rekey --vault-id @prompt /path/to/file
```

#### encrypt

```bash
$ ansible-vault encrypt --vault-id @prompt /path/to/file
```

#### decrypt

```bash
$ ansible-vault decrypt --vault-id @prompt /path/to/file
```

* decrypt from string

  ```bash
  # encrypt
  $ echo -n 'a' | ansible-vault encrypt_string
  Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)

  Encryption successful
  !vault |
            $ANSIBLE_VAULT;1.1;AES256
            63666334316139653431343330386139346466356439373263643566373062613666653362353738
            3630386133363464313964666230313062666662396161650a313165353966393136643932643434
            64306666613835333130613866303730623538313136323236653732663461623532343035626262
            3932643631653739350a306131666337633831653233623638396438386535623938626133653332
            3464

  # decrypt
  $ echo -n '$ANSIBLE_VAULT;1.1;AES256
  63666334316139653431343330386139346466356439373263643566373062613666653362353738
  3630386133363464313964666230313062666662396161650a313165353966393136643932643434
  64306666613835333130613866303730623538313136323236653732663461623532343035626262
  3932643631653739350a306131666337633831653233623638396438386535623938626133653332
  3464' | ansible-vault decrypt
  Decryption successful
  a
  ```

#### view

```bash
$ ansible-vault view --vault-id @prompt /path/to/file
```

### ansible-galaxy

> \[!NOTE|label:references:]
>
> * [\* Kubernetes Collection for Ansible](https://galaxy.ansible.com/kubernetes/core)
>   * [ansible-collections/kubernetes.core](https://github.com/ansible-collections/kubernetes.core)
>   * [kubernetes.core.k8s](https://github.com/ansible-collections/kubernetes.core/blob/main/docs/kubernetes.core.k8s_inventory.rst)
> * [kubernetes.core](https://galaxy.ansible.com/kubernetes/core)
>   * [kubernetes.core.k8s](https://docs.ansible.com/ansible/latest/collections/kubernetes/core/k8s_module.html#ansible-collections-kubernetes-core-k8s-module)
> * [Collections in the Kubernetes Namespace](https://docs.ansible.com/ansible/latest/collections/kubernetes/index.html)
> * [Kubernetes.Core](https://docs.ansible.com/ansible/latest/collections/kubernetes/core/index.html#plugins-in-kubernetes-core)
> * [installing roles and collections from the same requirements.yml file](https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-roles-and-collections-from-the-same-requirements-yml-file)
> * [helm – Manages Kubernetes packages with the Helm package manager](https://docs.ansible.com/ansible/2.9/modules/helm_module.html)
> * [The Inside Playbook](https://www.ansible.com/blog)
>   * [Creating Kubernetes Dynamic Inventories with kubernetes.core Modules](https://www.ansible.com/blog/creating-kubernetes-dynamic-inventories-with-kubernetes.core-modules)
>   * [\* Automating Helm using Ansible](https://www.ansible.com/blog/automating-helm-using-ansible)
>   * [k8s\_taint](https://www.ansible.com/blog/whats-new-in-the-ansible-content-collection-for-kubernetes-2.3)
>   * [Kubernetes Meets Event-Driven Ansible](https://www.ansible.com/blog/kubernetes-meets-event-driven-ansible)

```bash
$ ansible-galaxy collection install kubernetes.core

# or
$ ansible-galaxy install -r requirements.yml
```

* [example](https://docs.ansible.com/ansible/latest/collections/kubernetes/core/helm_module.html#examples)

  ```bash
  - name: Deploy latest version of Prometheus chart inside monitoring namespace (and create it)
    kubernetes.core.helm:
      name: test
      chart_ref: stable/prometheus
      release_namespace: monitoring
      create_namespace: true

  # From repository
  - name: Add stable chart repo
    kubernetes.core.helm_repository:
      name: stable
      repo_url: "https://kubernetes.github.io/ingress-nginx"

  - name: Deploy latest version of Grafana chart inside monitoring namespace with values
    kubernetes.core.helm:
      name: test
      chart_ref: stable/grafana
      release_namespace: monitoring
      values:
        replicas: 2

  - name: Deploy Grafana chart on 5.0.12 with values loaded from template
    kubernetes.core.helm:
      name: test
      chart_ref: stable/grafana
      chart_version: 5.0.12
      values: "{{ lookup('template', 'somefile.yaml') | from_yaml }}"

  - name: Deploy Grafana chart using values files on target
    kubernetes.core.helm:
      name: test
      chart_ref: stable/grafana
      release_namespace: monitoring
      values_files:
        - /path/to/values.yaml

  - name: Remove test release and waiting suppression ending
    kubernetes.core.helm:
      name: test
      state: absent
      wait: true

  - name: Separately update the repository cache
    kubernetes.core.helm:
      name: dummy
      namespace: kube-system
      state: absent
      update_repo_cache: true

  - name: Deploy Grafana chart using set values on target
    kubernetes.core.helm:
      name: test
      chart_ref: stable/grafana
      release_namespace: monitoring
      set_values:
        - value: phase=prod
          value_type: string

  # From git
  - name: Git clone stable repo on HEAD
    ansible.builtin.git:
      repo: "http://github.com/helm/charts.git"
      dest: /tmp/helm_repo

  - name: Deploy Grafana chart from local path
    kubernetes.core.helm:
      name: test
      chart_ref: /tmp/helm_repo/stable/grafana
      release_namespace: monitoring

  # From url
  - name: Deploy Grafana chart on 5.6.0 from url
    kubernetes.core.helm:
      name: test
      chart_ref: "https://github.com/grafana/helm-charts/releases/download/grafana-5.6.0/grafana-5.6.0.tgz"
      release_namespace: monitoring

  # Using complex Values
  - name: Deploy new-relic client chart
    kubernetes.core.helm:
      name: newrelic-bundle
      chart_ref: newrelic/nri-bundle
      release_namespace: default
      force: True
      wait: True
      replace: True
      update_repo_cache: True
      disable_hook: True
      values:
        global:
          licenseKey: "{{ nr_license_key }}"
          cluster: "{{ site_name }}"
        newrelic-infrastructure:
          privileged: True
        ksm:
          enabled: True
        prometheus:
          enabled: True
        kubeEvents:
          enabled: True
        logging:
          enabled: True
  ```

### ansible-playbook

> \[!NOTE|label:references:]
>
> * [passwordless via environment variables](https://docs.ansible.com/archive/ansible/2.5/user_guide/playbooks_vault.html)
> * <https://docs.ansible.com/ansible/latest/plugins/become.html#become-plugins>
> * sample:
>   * [gikeymarcia/ansible-role-neovim](https://github.com/gikeymarcia/ansible-role-neovim/blob/master/tasks/main.yml)

```bash
# without password
$ export ANSIBLE_VAULT_PASSWORD_FILE=/path/to/password.txt
$ ansible-playbook -i hosts /path/to/yaml

# with password
$ ansible-playbook -i hosts /path/to/yaml --vault-id @prompt
```

#### tags

> \[!NOTE|label:references]
>
> * [Special tags: always and never](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_tags.html#special-tags-always-and-never)
> * [Use Ansible tags to save time on playbook runs](https://www.redhat.com/sysadmin/ansible-tags-fast-playbook-runs)

**never**

```yaml
$ cat sample.yaml
---

- hosts: localhost
  gather_facts: False
  tasks:

    - name: Hello tag example
      debug:
        msg: "Hello!"
      tags:
        - hello

    - name: No tag example
      debug:
        msg: "How are you?"

    - name: Goodbye tag example
      debug:
        msg: "Goodbye!"
      tags:
        - goodbye
        - never                        # will not be executed unless using `--tags goodbye`
```

* result

  ```bash
  $ ansible-playbook sample.yaml

  PLAY [localhost] *************************************************************************
  TASK [Hello tag example] *****************************************************************
  ok: [localhost] => {
      "msg": "Hello!"
  }

  TASK [No tag example] ********************************************************************
  ok: [localhost] => {
      "msg": "How are you?"
  }

  PLAY RECAP *******************************************************************************
  localhost           : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  ```
* result with `--tags`

  ```bash
  $ ansible-playbook sample.yaml --tags goodbye

  PLAY [localhost] *************************************************************************

  TASK [Goodbye tag example] ***************************************************************
  ok: [localhost] => {
      "msg": "Goodbye!"
  }

  PLAY RECAP *******************************************************************************
  localhost           : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  ```

### vault CLI

> \[!NOTE|label:references:]
>
> * [Vault CLI commands](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-vault-cli)
> * [Vault commands (CLI)](https://developer.hashicorp.com/vault/docs/commands)
> * [Using Ansible command line tools](https://docs.ansible.com/ansible/latest/command_guide/index.html)

#### environment variables

```bash
$ export VAULT_ADDR=https://vault.example.com
$ export VAULT_TOKEN=s.s**********************K
```

#### [kv get](https://developer.hashicorp.com/vault/docs/commands/kv/get)

```bash
$ vault kv get -mount=project service-account/account
============= Secret Path =============
project/data/service-account/account

======= Metadata =======
Key                Value
---                -----
created_time       2024-06-19T06:51:35.036120169Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            9

============= Data =============
Key                       Value
---                       -----
email                     account@sample.com
password                  eW7[xRF(rgA@x)n£LN75?R5b.k2z1+
username                  account

# with json foramt
$ vault kv get -format=json -mount=project service-account/account
```

#### [kv list](https://developer.hashicorp.com/vault/docs/commands/kv/list)

```bash
$ vault kv list project/service-account
Keys
----
account
```

### [ansible-config](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#inventory-unparsed-warning)

> \[!NOTE|label:referencs:]
>
> * [v2.4 Configuration file](https://docs.ansible.com/archive/ansible/2.4/intro_configuration.html)
> * [Ansible Configuration Settings](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#envvar-ANSIBLE_VAULT_PAS)

#### get all default

```bash
$ ansible-config init --disabled -t all
```

* disable localhost warning

  ```bash
  $ cat ansible.cfg
  [defaults]
  localhost_warning=false
  ```

### ansible-lint

> \[!NOET|label:references:]
>
> * [Yamllint Indentation Warning on Valid Ansible code](https://stackoverflow.com/q/47417743/2940319) | [`indent-sequences: false`](http://yamllint.readthedocs.io/en/latest/rules.html#module-yamllint.rules.indentation)
> * [ansible-lint - Installing](https://ansible.readthedocs.io/projects/lint/installing/)
> * vim/nvim plugins
>   * [jctanner/ansible-tools](https://github.com/jctanner/ansible-tools)

* [Configuration](https://ansible.readthedocs.io/projects/lint/configuring/)
  * `.ansible-lint`
  * `.config/ansible-lint.yml`
  * `.config/ansible-lint.yaml`

### ansible-tools

> \[!NOTE|label:references:]
>
> * [jctanner/ansible-tools](https://github.com/jctanner/ansible-tools)

### plugin

#### [lookup](https://docs.ansible.com/ansible/latest/plugins/lookup.html)

> \[!NOTE|label:references:]
>
> * [自动化运维 | Ansible lookup](http://www.manongjc.com/detail/57-jamkqmdgyzomkhf.html)
> * sample code
>
>   ```bash
>   $ ls --color=none lookup* | xargs -n1 -t cat
>   cat lookup-content.txt
>   hello world
>
>   cat lookup.yaml
>   ---
>   - hosts: localhost
>     tasks:
>     vars:
>        contents: "{{ lookup('file', '/home/marslo/iMarslo/study/code/ansible/lookup-content.txt')}}"
>     tasks:
>        - debug: msg="the content of file lookup-content.txt is {{contents}}"
>   ```

```bash
$ ansible-playbook lookup.yaml
PLAY [localhost] *************************************************************************

TASK [Gathering Facts] *******************************************************************
Monday 24 July 2023  17:43:51 -0700 (0:00:00.007)       0:00:00.007 ***********
ok: [localhost]

TASK [debug] *****************************************************************************
Monday 24 July 2023  17:43:51 -0700 (0:00:00.935)       0:00:00.943 ***********
ok: [localhost] => {}

MSG:

the content of file lookup-content.txt is hello world

PLAY RECAP *******************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Monday 24 July 2023  17:43:52 -0700 (0:00:00.030)       0:00:00.974 ***********
===============================================================================
Gathering Facts ------------------------------------------------------------------- 0.94s
debug ----------------------------------------------------------------------------- 0.03s
```

#### [Become](https://docs.ansible.com/ansible/latest/plugins/become.html#become-plugins)

> \[!NOTE|label:references:]
>
> * [Understanding privilege escalation: become](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html#using-become)
> * [Ansible Become](https://learning-ocean.com/tutorials/ansible/ansible-become/)

### troubleshooting

* [generate the final yaml via `ansible.builtin.template`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html)

  ```yaml
  # in tasks/main.yaml
  - name: Template a file to local
    ansible.builtin.template:
      src: file_in_template.yaml
      dest: /local/path/to/yaml
  ```
