Ansible

From Ever changing code
Jump to navigation Jump to search

Ansible - management and configuration system

... watch the space :j

Install

apt-cache policy ansible | grep -A1 Installed # check version it will install
sudo apt-get install ansible

Install dependencies manually

sudo apt-get install python python-setuptools python-crypto python-jinja2 python-paramiko python-pkg-resources python-yaml python python-httplib2 python-netaddr

Download a version from Ansible git repository you need

wget https://releases.ansible.com/ansible/ansible-1.9.4.tar.gz
tar -xzvf ansible-1.9.4.tar.gz 
cd ansible-1.9.4/
sudo  make
sudo python setup.py install

Build VM with Vagrant

sudo apt-get install virtualbox

Then install Vagrant

Adhoc commands reference

                                                               --options
ansible*  host/-i hostfile -m modulename -a 'module arguments' -b (become) --ask-become-pass (-K in short)
                                                               
ansible local -m setup -a 'filter=ans*ipv4*'   #filter facts
ansible appsrv -m shell -a 'apt-get -y install lynx' -b --ask-become-pass  #-s deprecated replaced by -b 'become'
ansible appsrv -m apt -a 'pkg=lynx state=installed update_cache=true' -b -K
ansible appsrv -m file -a 'path=/tmp/etc state=directory mode=0700 owner=root' #create directory
ansible appsrv -m copy -a 'src=/etc/fstab dest=/tmp/etc/fstab'     #copy a file to a remote system
ansible appsrv -m command -a 'rm -rf /tmp/etc/fstab'               #delete a file
ansible appsrv -m service -a 'name=apache2 state=stopped' -u user -b -K #stop Ubuntu apache
ansible appsrv -m apt -a 'name=apache2 state=absent' -b --ask-become-pass #removes package

Specify a user that ansible control server should connect as, a key also can be specified but not necessary

$ ansible centos -m ping -u username --private-key=~/.ssh/id_rsa

Copy a user ssh public key to remote server, if you do not specify a username, the current user will be used

ssh-copy-id username@server.com

Execute a module against localhost

ansible all -i "localhost," -c local -m shell -a "apt-get remove git -y" --become
ansible all -i "localhost," -c local -m apt -a "pkg=git state=installed" --become

Modules

shell is not interactive, therefore 'apt-get install' requires -y flag. STDOUT is displayed on your terminal. The pipe and all redirections do work. Executes commands on a remote node.
copy - copies files from a local control server to remote node
fetch - copies files from remote node to the local box

Get facts

Examples of the most common facts. It requires Python to be installed on a remote node

ansible awsweb -m setup -a 'filter=ansible_distr*' -u user --become --ask-become-pass
ansible awsweb -m setup -a 'filter=ansible_fqdn'
ansible awsweb -m setup -a 'filter=ansible_interfaces'
ansible awsweb -m setup -a 'filter=ansible_kernel'
ansible awsweb -m setup -a 'filter=ansible_mem*'
ansible awsweb -m setup -a 'filter=ansible_proc*'

Config file lookup process

Nearly all parameters can be overridden in ansible-playbook or with command line flags. ansible will read ANSIBLE_CONFIG, ansible.cfg in the current working directory, .ansible.cfg in the home directory or /etc/ansible/ansible.cfg, whichever it finds first.

  1. export ANSIBLE_CONFIG=/home/test/config/ansible.cfg - environment variable
  2. current directory a command is run
  3. user home directory ~/.ansible.cfg
  4. /etc/ansible/ansible.cfg - it's ansible system config file

Prepare environment for automation

Make an ansible_service user to run sudo without password asked

sudo visudo
piotr ALL=(ALL)    NOPASSWD: ALL    #user can run as root without password
sudo -l    #check your rules, last rule take precedence

Stop Ansible to require sudo password at each run

sudo vi /etc/ansible/ansible.cfg
#ask_sudo_pass = True         #needs to be commented out, otherwise works like --ask-become-pass

Install ansible_service user ssh_keys on local host

ssh-copy-id localhost
ssh-copy-id localhost.localdomain

Variables used within playbooks - TARGET SECTION

Specific to a playbook by adding a section:

- hosts: awsweb
  vars: 
    controls_server: localhost
    web_root: /var/wwwroot
  tasks:
    - name: Task1

Include variables from files

- hosts: awsweb                                                #Example of variables file content:
  vars_files:                 cat ./vars.yml	
   - vars.yml   --------->    --- # YAML file
  tasks:                      controls_server: localhost
   - name: Task1              web_root: /var/wwwroot

Prompt a user to provide a value to the variable

- hosts: awsweb
  vars_prompt: 
    - name: controls_server     #variable name
      prompt: Provide Controls Serve name
  tasks:
    - name: Task1

Handlers section

In the example below handler 'Restart Apache' will be called only on change status of 'Install apache web server' task

tasks:
     - name: Install apache web server
       action: apt pkg=apache2 state=installed
       tags:
         - packages
       notify: Restart Apache         #notification matches the name of the handler
handlers:
     - name: Restart Apache
       action: service name=apache2 state=restarted
Execution order

Handlers are run in the order they are listed in a handlers file, not in the order that they are notified.

These ‘notify’ actions are triggered at the end of each block of tasks in a playbook, and will only be triggered once even if notified by multiple different tasks.

Variables passed at command line

Any variable can be passed at command line

ansible-playbook variable_fromcommandline.yml --extra-vars "hosts=awsweb user=user pkg=telnet"

Tags section

Run a specific part of the configuration without running the whole playbook. See the playbook example above tags section

ansible-playbook example.yml --tags "configuration,packages"  #will run only tags sections
ansible-playbook example.yml --skip-tags "notification" #skips tagged sections

There is a special always tag that will always run a task, unless specifically skipped (–skip-tags always)

Start at task and step

ansible-playbook example.yml --start-at-task="Name of task"  #execute a playbook from this taks to the EOF
ansible-playbook example.yml --step #will step you through, asking y/n/c for each task

Conditional statements and loops

wait_for
- name: Wait for port 80 is listening
  wait_for:
    port: 80
    state: started
until

The play below will loop until: find a string in shell: output.

- name: Check if HTTPD is running
  shell: system status httpd
  register: result
  until: result.stdout.find("active (running)")    #search string
  retries: 5    #in seconds
  delay: 5

Roles

Roles are automation around include directives. Therefore directories like tasks, handlers, vars and meta are automatically included as long the 'main.yml' file is there. There is no need to reference them using referenced or absolute paths, they are automatically available and included in plays.

The main.yml file contains all directives relevant to the uppper directory it is in, can contain a list of tasks, handles or vars.

Let's assume you have structure like this

site.yml
webservers.yml  <- eg. master control file recalls 'roles' named as a directory in roles/rolename
fooservers.yml
roles/
   common/           webservers/           
     files/            files/         - files used locally or transferred to a remote node    
     templates/        templates/     - Jinja2 templates
     tasks/            tasks/         - (include) individual tasks that play will do something
     handlers/         handlers/      - (include) eg. server restarts, shared among tasks
     vars/             vars/          - (vars) binary values something equals something else
     defaults/         defaults/      - default settings
     meta/             meta/          - (vars) roles dependencies

In a playbook (eg. webservers.yml), it would look like this:

---
- hosts: webservers
  roles:
     - common
     - webservers

This designates the following behaviors, for each role 'x':

  • If roles/x/tasks/main.yml exists, tasks listed therein will be added to the play
  • If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play
  • If roles/x/vars/main.yml exists, variables listed therein will be added to the play
  • If roles/x/meta/main.yml exists, any role dependencies listed therein will be added to the list of roles
    • Any copy, script, template or include tasks (in the role) can reference files in roles/x/{files,templates,tasks}/ (dir depends on task) without having to path them relatively or absolutely

Execution order

In a play any roles always execute before tasks. To manipulate the flow you can use pre_ and post_ directives

---
- hosts: awsweb
  pre_tasks:
   - name: When the ROLE start
     raw: date > role_start-end.log
  roles:
   - webservers
  post_tasks:
   - name: When the ROLE end
     raw: date >> role_start-end.log

Roles path

You make roles system-wide available by including its path in /etc/ansible/ansible.cfg file

roles_path    = /home/test/playbooks/roles:/etc/ansible/roles

By default, a playbook that calls a role searches relative directories:

./roles/name_of_role/
./name_of_role/

Ansible Vault

ansible-vault create secure.yml   #give a password that will be used as an encryption key
ansible-vault rekey secure.yml    #change a password
ansible-vault decrypt secure.yml  #decrypt the file
ansible-vault encrypt secure.yml  #encrypt existing file, can pass multiple files at once

Use Vault with playbooks

ansible-playbook secure.yml --ask-vault-pass

README.md - markdown format

.md stands for markdown and is generated at the bottom of your github page as html Typical syntax includes:

Will become a heading
==============

Will become a sub heading
--------------

*This will be Italic*
**This will be Bold**

- This will be a list item
- This will be a list item

      Add an indent and this will end up as code

Reference