Slide 1

Slide 1 text

Tools for Testing Ansible Roles/Playbooks And Why You Should Use Them Roderick R. Randolph

Slide 2

Slide 2 text

Who am I Roderick R. Randolph Opinions expressed are solely my own and do not express the views or opinions of my employer. /roderickrandolph •RRR •Raised in Amelia County, VA •Lived in Toronto for 2 years •Employed by Capital One •DevOps Architect

Slide 3

Slide 3 text

This Talk •Why Ansible •What are Ansible Roles •Importance of Testing Ansible Roles •Tools for Testing Ansible Roles •Live Demo

Slide 4

Slide 4 text

What is Ansible? Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates. http://docs.ansible.com/ansible/

Slide 5

Slide 5 text

Ansible Goals • Easy to Use No agent to install or configure • Simple Describe desired state in human-readable YAML • Secure and Reliable Uses industry standard OpenSSH utilities • Extensible Create custom modules to make Ansible even more powerful

Slide 6

Slide 6 text

# playbook.yml --- - hosts: all tasks: - name: install nginx package yum: name: nginx state: present - name: start nginx server systemd: name: nginx enabled: yes state: started Your First Playbook

Slide 7

Slide 7 text

Image Credit: https://flic.kr/p/5rQphw

Slide 8

Slide 8 text

A Month Later…

Slide 9

Slide 9 text

--- - hosts: all tasks: - name: install nginx package yum: name: nginx state: present when: ansible_os_family == 'RedHat' - name: install nginx package apt: name: nginx state: present when: ansible_os_family == 'Ubuntu' - name: copy nginx configuration in place template: src: "{{item}}.j2" dest: /etc/nginx/main.d/{{item}} mode: 0644 with_items: - nginx.conf - vhosts.conf - name: create source directory file: path: /src state: directory mode: 0755 - name: copy source code copy: src: "{{lookup('pipe', 'dirname `pwd`')}}/{{item}}" dest: /src/{{item}} with_items: - package.json - app.js - name: install npm packages npm: path: /src state: latest production: yes - name: RedHat - Ensure Java is installed yum: name: "{{ java }}" state: "present" update_cache: yes when: ansible_os_family == 'RedHat' # - name: Debian - Refresh java repo # apt: update_cache=yes # changed_when: false # when: ansible_os_family == 'Debian' - name: Debian - Ensure Java is installed apt: name={{ java }} state="present" when: ansible_os_family == 'Debian' - name: Check java version command: java -version 2>&1 | grep OpenJDK register: open_jdk changed_when: false # https://github.com/docker-library/openjdk/issues/19 - ensures tests pass due to java 8 broken certs - name: refresh the java ca-certificates command: /var/lib/dpkg/info/ca-certificates-java.postinst configure when: ansible_distribution == 'Ubuntu' and open_jdk.rc == 0 changed_when: false - name: install tomcat package yum: name: tomcat state: present when: ansible_os_family == 'RedHat' - name: install tomcat package apt: name: tomcat state: present when: ansible_os_family == 'Ubuntu' - name: install java app on server copy: src: app.war dest: /usr/share/tomcat/webapps/app.war - name: start nginx server systemd: name: nginx enabled: yes state: started with_items: ['nginx', 'tomcat']

Slide 10

Slide 10 text

Image Credi: https://flic.kr/p/7NJh8

Slide 11

Slide 11 text

Ansible offers a powerful DSL • Variables Manage data values and differences between systems • Conditionals Skip tasks based on value of variables • Loops Repeat things in one task • Templating Create dynamic expressions, filters, lookups, and tests

Slide 12

Slide 12 text

Image Credit: https://bit.ly/2mLWAmu

Slide 13

Slide 13 text

Ansible Playbook "Code Smell" • Duplicate tasks • Large number of tasks Minimize the number of tasks to 5-6 per play • Complex loops and conditionals Ansible is not a substitute for a programming language • Hard coded variables / inconsistent naming conventions • Heavy tight coupling between roles • No tests

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

# playbook.yml --- - hosts: all roles: - nginx - tomcat - newrelic - fluentd Refactor To Use Ansible Roles

Slide 17

Slide 17 text

Ansible Roles • Provide a layer of abstraction to help organize playbook tasks (improve readability and intent) • Create reusable and common tasks that can be shared across playbooks (minimize duplication) • Breaks playbook into smaller unit of work (reduced complexity) • Can be tested independently

Slide 18

Slide 18 text

# playbook.yml --- - hosts: all roles: - newrelic - fluentd tasks: - import_role: name: nginx - include_role: name: tomcat Mix Ansible Roles With Tasks

Slide 19

Slide 19 text

Image Credit: https://flic.kr/p/77B38H

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Importance of Testing Ansible Roles • Higher quality roles Easy to maintain, extend, comprehend • Increased confidence Fewer bugs and rework • Validate Ansible upgrade compatibility • Self-documented example use cases

Slide 23

Slide 23 text

Testing Strategies for Ansible • Unit testing Performed at the Ansible module-level • Functional testing Use Ansible to test Ansible! • Integration testing Ensures roles work together as intended

Slide 24

Slide 24 text

Tools for Testing Ansible Roles

Slide 25

Slide 25 text

https://www.ansible.com/

Slide 26

Slide 26 text

Testing Ansible with Ansible # playbook.yml --- - hosts: all tasks: - wait_for: host: "{{ inventory_hostname }}" port: 8080 delegate_to: localhost

Slide 27

Slide 27 text

Testing Ansible with Ansible # playbook.yml --- - hosts: all tasks: - uri: url: http://www.example.com return_content: yes register: webpage - fail: msg: website is unavailable when: "'AWESOME' not in webpage.content"

Slide 28

Slide 28 text

Testing Ansible with Ansible # playbook.yml --- - hosts: all tasks: - shell: /usr/bin/some-command --parameter value register: command_results - assert: that: website is unavailable - "'not ready' not in command_results.stderr" - "'gizmo enabled' in command_results.stdout"

Slide 29

Slide 29 text

https://github.com/metacloud/molecule

Slide 30

Slide 30 text

Testing Ansible with Molecule --- dependency: name: galaxy driver: name: docker lint: name: yamllint platforms: - name: centos7 image: milcom/centos7-systemd privileged: True provisioner: name: ansible scenario: name: default verifier: name: testinfra $ molecule lint $ molecule syntax $ molecule setup $ molecule idempotence $ molecule destroy ... --> Scenario: 'default' --> Action: 'lint' --> Executing Yamllint on files found... Lint completed successfully. --> Executing Flake8 on files found... Lint completed successfully. --> Executing Ansible Lint on... Lint completed successfully.

Slide 31

Slide 31 text

https://kitchen.ci/

Slide 32

Slide 32 text

Testing Ansible with Test Kitchen --- driver: name: ec2 provisioner: name: ansible_playbook platforms: - name: ubuntu-16.04 - name: centos-7 suites: - name: default verifier: name: inspec $ kitchen create $ kitchen converge $ kitchen setup $ kitchen verify $ kitchen destroy --> Running rspec test suites ✔ git binary is found in PATH 3 tests, 2 failures Finished verifying (0m0.98s). --> Destroying --> Kitchen is finished. (1m44.11s)

Slide 33

Slide 33 text

Image Credit: https://flic.kr/p/JykJBD

Slide 34

Slide 34 text

Wrap Up • Ansible playbooks and roles should be treated as code • Refactor playbooks to use ansible roles and avoid code smell • Use test tools to verify your Ansible roles to increase your confidence

Slide 35

Slide 35 text

Image Credit: https://flic.kr/p/47z3PA