Tech/OSS/Ansible/Guide
I started a 101 class thing at https://lathama.net/git/lathama/Ansible101 but was not getting to it often. It may be better as wiki pages.
Ansible Guide
Introduction
A basic setup to teach people how to get started without making a mess. This is written for use on a modern Linux system.
Installation
Installation via the Python PIP tool looks like:
lathama@desky:~/Ansible101$ python3 -m pip install -qq --user --upgrade ansible
To break down this command into its parts:
python3 -m pip
is the current best practice for scripts.pip3
should work the same from the CLIinstall -qq
quietly install and answer yes to prompts--user
install in the user home (no root user required)--upgrade
upgrade the package or dependencies if installed
Confirm the install with:
lathama@desky:~/Ansible101$ ansible --version
ansible [core 2.14.4]
config file = /home/lathama/Ansible101/ansible.cfg
configured module search path = ['/home/lathama/Ansible101/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/lathama/.local/lib/python3.9/site-packages/ansible
ansible collection location = /home/lathama/Ansible101/.ansible/collections:/usr/share/ansible/collections
executable location = /home/lathama/.local/bin/ansible
python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True
In some cases you may need to completely log out and log back in to have the PATH set correctly
Configs and Setup
Note the included ansible.cfg that sets the paths for this demo. A vault passphrase is the only thing missing from the demo by default.
lathama@desky:~/Ansible101$ echo "topsecret" > .ansible_vault
Command Line Interface (CLI)
Ansible has many CLI tools
- ansible
- ansible-community
- ansible-config
- ansible-connection
- ansible-console
- ansible-doc
- ansible-galaxy
- ansible-inventory
- ansible-playbook
- ansible-pull
- ansible-test
- ansible-vault
References
- Installation Manual https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
Ad hoc
Ad hoc commands are useful. By default Ansible will create a python script. The ansiballz script will be sent to the host to execute.
Confirm SSH first
We will start with localhost. If you have issues connecting to localhost then further Ansible setup will be difficult/impossible. We are assuming you have the user password or have SSH keys setup.
lathama@desky:~/Ansible101$ ssh localhost whoami
lathama
Raw command does not need Python Interpreter on target
lathama@desky:~/Ansible101$ ansible localhost -m raw -a whoami
localhost | CHANGED | rc=0 >>
lathama
Shared connection to localhost closed.
Simple command using Python ansiballz
lathama@desky:~/Ansible101$ ansible localhost -a whoami
localhost | CHANGED | rc=0 >>
lathama
Target tmp empty
lathama@desky:~/Ansible101$ ls ~/.ansible/tmp
Keep remote file
lathama@desky:~/Ansible101$ ANSIBLE_KEEP_REMOTE_FILES=1 ansible localhost -a whoami
Target tmp ansiballz
As a learning moment, have a look at the ansiballz that is created on the target
lathama@desky:~/Ansible101$ ls ~/.ansible/tmp
ansible-tmp-1681314397.595484-476223-48384824394074
lathama@desky:~/Ansible101$ cat ~/.ansible/tmp/ansible-tmp-id/AnsiballZ_command.py | wc -l
259
lathama@desky:~/Ansible101$ grep whoami ~/.ansible/tmp/ansible-tmp-id/AnsiballZ_command.py
ANSIBALLZ_PARAMS = '{"ANSIBLE_MODULE_ARGS": {"_raw_params": "whoami", "_ansible_check_mode": false,
"_ansible_no_log": false, "_ansible_debug": false, "_ansible_diff": false, "_ansible_verbosity": 0,
"_ansible_version": "2.14.4", "_ansible_module_name": "ansible.legacy.command",
"_ansible_syslog_facility": "LOG_USER", "_ansible_selinux_special_fs": ["fuse", "nfs", "vboxsf",
"ramfs", "9p", "vfat"], "_ansible_string_conversion_action": "warn", "_ansible_socket": null,
"_ansible_shell_executable": "/bin/sh", "_ansible_keep_remote_files": true,
"_ansible_tmpdir": "/home/lathama/.ansible/tmp/ansible-tmp-id/",
"_ansible_remote_tmp": "~/.ansible/tmp"}}'
References
New and Old
To demonstrate some flexibility we will connect to a very old Cisco switch. You may not have a device like this. You will find situations when you need to automate a legacy device so understanding this will help.
Validate via SSH
First we will validate via SSH on the CLI. Note the options we must pass to enable old ciphers for this host.
lathama@desky:~/Ansible101$ ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 -o HostKeyAlgorithms=+ssh-dss -c aes256-cbc cisco@192.168.1.9
Password:
SGM-DEN-PSW-011.LATHAMA.NET#dir
Directory of flash:/
2 -rwx 11832064 Jan 1 1970 00:20:44 +00:00 c2960-lanbasek9-mz.150-2.SE10.bin
3 -rwx 1806 Sep 1 2020 17:55:47 +00:00 config.text
4 -rwx 15556 Sep 1 2020 17:55:47 +00:00 private-config.text
5 -rwx 3096 Sep 1 2020 17:55:47 +00:00 multiple-fs
27998208 bytes total (16046080 bytes free)
SGM-DEN-PSW-011.LATHAMA.NET#exit
Connection to 192.168.1.9 closed.
Inventory
An example from the inventory/inventory.yml
---
oldcisco:
ansible_ssh_common_args: '-o KexAlgorithms=+diffie-hellman-group1-sha1 -c aes256-cbc'
ansible_host: '192.168.1.9'
ansible_user: 'cisco'
ansible_password: 'topsecret'
A playbook
An example from playbooks/legacy.yml
---
# login to a really old Cisco switch and get some info
# using the raw command to list the directory
# we are making no changes so we ignore changes
# printing out the result we only want the stdout_lines
- name: 'Legacy device info'
hosts: oldcisco
gather_facts: false
tasks:
- name: 'List filesystem'
ansible.builtin.raw: 'dir'
changed_when: false
register: result
- name: 'Print out the directory'
ansible.builtin.debug:
var: result.stdout_lines
Run the playbook
lathama@desky:~/Ansible101$ ansible-playbook playbooks/legacy.yml
PLAY [Legacy device info] ****************************************************************************************
TASK [List filesystem] *******************************************************************************************
ok: [oldcisco]
TASK [Print out the directory] ***********************************************************************************
ok: [oldcisco] => {
"result.stdout_lines": [
"Directory of flash:/",
"",
" 2 -rwx 11832064 Jan 1 1970 00:20:44 +00:00 c2960-lanbasek9-mz.150-2.SE10.bin",
" 3 -rwx 1806 Sep 1 2020 17:55:47 +00:00 config.text",
" 4 -rwx 15556 Sep 1 2020 17:55:47 +00:00 private-config.text",
" 5 -rwx 3096 Sep 1 2020 17:55:47 +00:00 multiple-fs",
"",
"27998208 bytes total (16046080 bytes free)"
]
}
PLAY RECAP *******************************************************************************************************
oldcisco : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Conclusion
Note how simple it is to add a unique legacy system to the inventory and work with it.
References
- Inventory https://docs.ansible.com/ansible/latest/network/getting_started/first_inventory.html
- Debug Module https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html
- SSH Common Args https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ssh_connection.html#parameter-ssh_common_args
Files
- ansible.cfg which you can learn about by running ansible-config init --disabled -t all > ansible_full.cfg
- inventory.yaml
Terms
- Idempotent / Idempotence
- https://en.wikipedia.org/wiki/Idempotence
- Andrew says "After initial use, the operation makes no changes in additional runs"