Ansible

AWX

  • Ansible awx check functionality
  • Check what is needed for installation/scalability/expanding
  • Memcache requirements
  • DB requirements
  • Web requirements
  • Run via docker
  • Create it as a microservice system
  • Create a role which will creat a lamp server
  • Check git integration
  • Check Bitbucket integration
  • Env usage
  • Download output of ansible playbook is not working,maybe cause of network

Install ansible version in virtualenv

check all versions of ansible

pip install ansible==?

create virtualenv

virtualenv ansible-2.0.2.0

activate 2.0.2.0 and enter into virtualenv

root@jmaster:/opt# source ansible-2.0.2.0/bin/activate
(ansible-2.0.2.0) root@jmaster:/opt#

install ansible-2.0.2.0

(ansible-2.0.2.0) root@jmaster:/opt# pip install ansible==2.0.2.0

deactivate 2.0.2.0, it will also exit from virtualenv

(ansible-2.0.2.0) root@jmaster:/opt# deactivate
root@jmaster:/opt#

Inventory

  • dynamic inventory script is executed only at the begging of the playbook
  • add_host module - adds host to the inventory but only for the duration of the execution of the playbook.It will not modify your inventory file
    • add new host to the group test with connection options and var foo=42

dynamic inventory ( works with ansible version 2.5.5 )

EC2_INI_PATH=./inventory/ec2.ini EC2_INSTANCE_FILTERS='tag:Environment=maint' AWS_PROFILE=${PROFILE} AWS_DEFAULT_REGION=${REGION} ansible -i inventory/ec2.py all
- add_host:
    hostname: "{{ new_ip }}"
    ansible_host: "{{ inventory_hostname }}"
    ansible_port: "{{ new_port }}"
    foo: 42
    groups: test
  • group_by - Use facts to create ad-hoc groups that can be used later in a playbook.
- name: Create groups based on the machine arch 
   group_by: key=machine_{{ ansible_machine }}

Behavioral inventory parameters

  • ansible_port
  • ansible_user
  • ansible_ssh_private_key_file
  • ansible_host
  • ansible_connection - smart,ssh,paramiko ( other options are local and docker )
  • ansible_*_interpreter
  • ansible_python_interpreter
host var1 var2
some_host ansible_port=2222 ansible_user=manager
aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host ansible_python_interpreter=/usr/local/bin/python
ruby_module_host ansible_ruby_interpreter=/usr/bin/ruby.1.9.3

Jinja2

  • if clause:
{% if tls_enabled %}
listen 443;
{% endif %}
  • if domains are configured as list:
domains: 
  - AAAA
  - BBBB
  • in jinja2 a list can be converted to a string via join
{{ domains|join(", ") }} => AAAA, BBBB

Terms

  • Play - logical entity which connects hosts to tasks.Each play must have set of hosts to configure and list of tasks to be executed on those hosts

  • Playbook - describes which hosts to configure ( aka executable documentation ). List of dictionaries/plays ( key, value pairs )

  • Tasks - what actions to perform on the target nodes

  • Modules - are declarative ( use them to describe the state you want the server to be ). Also, they are idempotent ( can be run multiple times )

  • Roles folder - collecting playbooks together

  • Ansible Galaxy - online repositories for roles

  • Files folder - keeping static files

  • Templates folder - keeping dynamic files

  • Handlers folder - similar to task but it only runs if it has been notified by task.They only run after all of the tasks are run, and they only run once, even if they are notified multiple times. They always run in the order that they appear in the play, not the notification order.

  • inventory ( folder,file or script ) - collection of hosts that Ansible knows about

  • host_vars - folder which Ansible looks for a host variable files

  • group_vars - folder which Ansible looks for a group variable files

  • library - folder which Ansible looks for custom modules

Variables

String vars don’t need quoting

- name: copy TLS key and cert
      copy:
        src: files/{{ item }}
        dest: /etc/nginx/ssl/{{ item }}
        owner: root
        mode: 0600

On the other hand, always quote template expression brackets when they start a value. For instance:

    with_items:
      - {{ foo }}

Should be written as:

    with_items:
      - "{{ foo }}"

Using Variables

  • register - to store a value as an registered value. The value of a variable set using the register clause is always a dictionary, but the specific keys of the dictionary are differnet ( depending on the module )
  • ignore_errors = yes|no - in case we want to ansible continue with other tasks
  • local_facts - on remote hosts we can create example.fact files in /etc/ansible/facts.d/ which can be used as local variables of dict ansible_local *
  tasks:
    - name: print ansible_local
      debug: var=ansible_local

    - name: print book title
      debug: msg="The title of the book is {{ ansible_local.example.book.title }}"
  • set_fact - define a new variable ( recommended to use it after register )
  • built_in variables
    • hostvars - a dict whose keys are ansible host names and values are dicts that map variables names to values
      • following example will print vars from vagrant1 host ( var=hostvars[inventory_hostname] can be used also )
$ ansible vagrant1 -m debug -a "var=hostvars['vagrant1']"
vagrant1 | SUCCESS => {
    "hostvars['vagrant1']": {
        "ansible_host": "127.0.0.1",
        "ansible_port": 2222,
        "ansible_version": {
            "full": "2.0.2.0",
            "major": 2,
            "minor": 0,
            "revision": 2,
            "string": "2.0.2.0"
        },
        "group_names": [
            "vagrant"
        ],
        "groups": {
            "all": [
                "vagrant1"
            ],
            "ungrouped": [],
            "vagrant": [
                "vagrant1"
            ]
        },
        "inventory_dir": "/Users/xxx/dev/test",
        "inventory_file": "hosts",
        "inventory_hostname": "vagrant1",
        "inventory_hostname_short": "vagrant1",
        "omit": "__omit_place_holder__916ed76f4177e6fedabb6c8b0d32d0c91cab2c66",
        "playbook_dir": "."
    }
}

  • inventory_hostname - name of the current host as known by ansible ( alias from inventory )
  • group_names - a list of groups that the current host is a member of
  • groups - a dict whose keys are ansible group names and values are a list of hostnames that are members of the group
  • play_hosts - a list of inventory hostnames which are active in the current play
  • ansible_version - a dict with ansible version info

Passing variables on the CLI

  • setting regular key=var
    • ansible-playbook greet.yml -e greeting=test
  • passing boolean variable
    • ansible-playbook great.yml -e "{greetoing: True}"
  • passing var which has space in var
    • ansible-playbook greet.yml -e 'greeting="test 1"'
  • passing vars from vars file
    • ansible-playbook greet.yml -e @greetvars.yml

Precedence from top to bottom

  1. ansible-playbook -e var=value
  2. Everything else not mention on the list
  3. On a host or group, either defined in inventory file or YAML file
  4. Facts
  5. In defaults/main.yml of a role

Passing environment variables to ansible tasks

Ansible allows you to set environment variables by adding an envinronment clause to a ANY task, passing it a dictionary that contains the env variable names and values.

- name: set the site id
  script: scripts/setsite.py
  environment:
    PATH: "{{ venv_path }}/bin"
    PROJECT_DIR: "{{ proj_path }}"
    WEBSITE_DOMAIN: "{{ live_hostname }}"

Workflow and facts

  • Ansible will make SSH connections in parallel to target nodes (if not configured otherwise).

  • Each task will be executed on the list of all nodes simultaneously.

  • Ansible waits until all hosts have completed a task before moving to the next task.

  • Ansible runs the tasks in the order that you specify them

  • Ansible will execute a task on a host by generating a custom script based on the module name and arguments, and then copies this script to the host and runs it.

  • Ansible looks for and ansible.cfg file in the following places, in this order:

    • File specified by the ANSIBLE_CONFIG env
    • ./ansible.cfg in the current folder » recommended
    • ~/.ansible.cfg in your home folder
    • /etc/ansible/ansible.cfg
  • Ansible uses /etc/ansible/hosts as the default location for the inventory file.

  • YAML playbooks settings: True, False

- name: configure something ...
  become: True
  • Module passing arugments: yes, no
- name: install nginx
  apt: name=nginx state=present update_cache=yes
  • If you are specifying an octal value as a complex argument, it must either start the value with a 0 or quote it as a string:
- name: copy index.html
  copy:
     src: files/index.html
     dest: /usr/share/nginx/html/index.html
     mode: "0644"
  • inventory_hostname - name of the remote host during the playbook run
  • Multiple conditions that all need to be true (a logical ‘and’) can also be specified as a list:
tasks:
  - name: "shut down CentOS 6 systems"
    command: /sbin/shutdown -t now
    when:
      - ansible_distribution == "CentOS"
      - ansible_distribution_major_version == "6"

Clause

  • with_items - when we have a list of items to do something with them. Ansible always uses item as the name of the loop iteration variable
  • when: {{ some_var }} - is true task will be executed
  • only present on command and shell
    • chdir - change to target directory before running the command
    • creates - A filename or (since 2.0) glob pattern, when it already exists, this step will not be run.
  • local_action - run a particular task on the control machine instead of on the remote host
  • serial - restrict the number of hosts that a play runs on
  • delegate_to - run the task on the different host
  • max_fail_percentage - specify max % of failed hosts before Ansible fails the entire play ( it is used in combination with serial )
  • run_once - run the command only once
  • failed_when - specify when the task is in failed state.If this clause is set to False the play will be continued
  • fail - instruct play to stop executing ( can be used with debug+register+failed_when=False)
- name: initialize the db
    django_manage:
      command: createdb --noinput --nodata
      app_path: ....
    failed_when: False
    register: result

 - name: debug the result output
    debug:
       var: result

 - name: stop the execution of the play   
   fail:
     msg: "something went wrong"
  • changed_when - Sometimes you will know, based on the return code or output that it did not make any changes, and wish to override the “changed” result such that it does not appear in report output or does not cause handlers to fire
  • args - it is used to explicitly pass named parameters to actions that support “free form” parameter – additional word args is required because in YAML (language used for Ansible playbooks) you can’t assign string value for “root” key of a dictionary.

here command is a string

command: /bin/echo ok

here user is a dict

user:
  name: john

And because command is a string, you use args to pass additional parameters (like chdir, creates, etc). Whereas user is a dict, so you can add parameters straight in there (like name, uid, etc).

  • vars_prompt - is useful if you need to provide a variable at run time — e.g. a password for a service and don’t want to source it from a vaulted file.
- hosts: certificate_authority

  vars_prompt:
  - name: ca_password
    prompt: "Please enter your CA password"

  tasks:
  - name: sign certificate
    command: openssl ca -in req.pem \
      -out newcert.pem -passin env:CA_PASSWD
    environment:
      CA_PASSWD: "{{ ca_password }}"

Modules

  • wait_for - waits for a condition before continuing

Lookups

All Ansible lookup plug-ins execute on the control machine, not the remote host.

  • file - contents of a file
  • password - randomly generate a password
  • pipe - output of locally executed command
  • env - environment variable
  • template - jinja2 template after evaluation
  • csvfile - entry in a .csv file
  • dnstxt - DNS TXT record
  • redus_kv - redis key lookup
  • etcd - etcd key lookup

Making Ansible faster

  • ControlMaster - Enables the sharing of multiple sessions over a single network connection
  • ControlPersist - When used in conjunction with ControlMaster, specifies that the master connection should remain open in the background (waiting for future client connections) after the initial client connection has been closed
  • ControlPath - Specify the path to the control socket used for connection sharing as described in the ControlMaster section above or the string “none” to disable connection sharing
  • Pipelining - allow execution the Python script by piping it to the SSH instead of copying it
  • Fact caching - enables or disables fact caching (by default it will be stored in memory)
[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_fact_cache

[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o ForwardAgent=yes
control_path = %(directory)s/%%h-%%r
pipelining = True