ansible tips & tricks

26
Tips & Tricks Not your usual usage Ansible Fest NYC 2015

Upload: bcoca

Post on 08-Aug-2015

4.242 views

Category:

Technology


0 download

TRANSCRIPT

Tips & TricksNot your usual usage

Ansible Fest NYC 2015

#>whoami

● currently: ansible core team member (bcoca)

● helpdesk/application support

● programmer/analyst/software engineer

● QA, systems & network administrator

● release manager, DBA, information security,

● “Tech Janitor”

#>apropos ansible

● Configuration management

● Release management

● Automation framework

● Orchestration system

● Distributed batch executor

____________________/ It runs a TASK * x \ \ on a HOST * x / -------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||

#LIVE>multiply_shell

● allows you to reuse your shell magic

● must be non interactive

● plays well with traditional unix tools

● just multiply by ### hosts

● requires some work for nicer outputs

● -t == json file database per host

#LIVE>ansible_shell#>ansible webs -m shell -a "awk '{print \$9}' /var/log/nginx/access.log|sort |uniq -c |sort -k1,1nr 2>/dev/null|column -t"

web1 | success | rc=0 >>204417 20048108 3048550 3026541 3011696 404269 206

web2 | success | rc=0 >>205807 20043762 304

...

#LIVE>procmail-- procmail

:0 #send back http code live report

* ^From.*@example.com* ^Subject:.*500 report

|ansible-playbook ~/plays/report.yml

--- #report.yml

- shell: "awk '{print \$9}' …

register: report

- mail: to={{lookup(‘env’,’FROM’)}} body={{report}} …

______________ < you got mail > -------------- \ , , \ /( )` \ \ \___ / | /- _ `-/ ' (/\/ \ \ /\ / / | ` \ O O ) / | `-^--'`< ' (_.) _ ) / `.___/` / `-----' /<----. __ / __ \<----|====O)))==) \) /====<----' `--' `.__,' \ | | \ / ______( (_ / \______ ,' ,-----' | \ `--{__________) \/

#UTIL>small_scripts

● tries not to be a programming language

● but … sometimes its very useful as such

● plays can wrap existing roles/task lists

● vars_prompt/pause allow for interactivity

● -e “var=val” for completely batch

● -e @file.json: you can use json data files

#UTIL>/sbin/departed#!/usr/bin/ansible-playbook---- name: Ensure only valid users hosts: all gather_facts: False sudo: True

vars_files: #departed: [ alan, bcoca, isaac, mathew, willy ] - /etc/departed_users.yml tasks: - name: Delete departed user and all it’s files user: name={{item}} state=absent remove=yes with_items: “{{departed}}”

#UTIL>/bin/release_apps#!/usr/bin/ansible-playbook

- hosts: localhost vars_prompt: - name: app_name prompt: “Which app do you want to deploy?” - name: app_version prompt: “Choose version/tag (default HEAD)” default: ‘HEAD’ tasks: - git: repo=git@myreposerver/{{app_version}} version={{app_version}} ......

- hosts: app_servers serial: 1 tasks:

- pause: "are you sure you want to stop all services?"

- name: shush nagios nagios: action=silence host={{inventory_hostname}} delegate_to: {{monitor}}

- name: nginx graceful stop service: name=nginx state=stopped

- name: stop uwsgi service name=uwsgi state=stopped …

...

______________________/ for reusability, use \\ includes and roles / ---------------------- \ \ __ UooU\.'@@@@@@`. \__/(@@@@@@@@@@) (@@@@@@@@) `YY~~~~YY' || ||

#QA>verify

● The same way I do things , I can check them

● Gentle learning curve for your test creator

● Checks don’t normally need root

● check_mode and diff_mode

● assert/fail, no need to read the output!

#QA>check_server- hosts: app_server

tasks:

- users: name=appuser state=present

name: verify that app user is present

- file: path=/to/app/dir owner=appuser mode=0700

name: check that app dir has proper permissions

- service: name={{item}} state=started

name: check that services are running

with_items: [‘nginx’, ‘uwsgi’]

- postgres_user: name=dbapp1 password=secretrole_attr_flags=NOSUPERUSER name: check app user is accessible via app server

____________________________________ / or if your playbook is idempotent, \\ just run it again Sam! / ------------------------------------ \ \ \ \ /\ ( ) .( o ).

#QA>check_app- hosts: app_servers

tasks:

- stat: path=/var/run/tomcat/webapps/myapp.jar

register: jar

- assert:

that:

- jar.checksum == lookup(‘consul_kv’,‘myapp_csum’)

- stat: path=/var/run/app2.pid

- wait_for: port=8080

- uri: return_content=’app1 OK’

#AUDIT>verify --- qa?

● The same way I do, I can check

● Gentle learning curve for your auditor

● Checks don’t normally need root

● check_mode and diff_mode

#AUDIT>check_firewall# verify firewall after manual config

- wait_for:

port: “{{item}}”

host: prod.example.com

delegate_to: outside.host.com

with_items: [‘80, ‘443’]

- wait_for: port={{item}} host=prod.example.com

delegate_to: outside.host.com

failed_when: not left_door_open|failed

register: left_door_open

when: item not in [‘80’, ‘443’]

with_sequence: start=1 end=1024

______________ < or call nmap > -------------- \ \ ___ {~._.~} ( Y ) ()~*~() (_)-(_)

#AUDIT>check_file_changes # from vars today_file: checks/{{inventory_hostname}}/{{today}}.txt

- find: paths=/etc recurse=Y size=1 age=1d

registered: fchanged

- assert:

that:

- fchanged|length == 0

- assert:

that:

- item.checksum == lookup(‘pipe’, ‘grep ‘ + item + ‘ /checks/latest| cut -f2’)

with_items: “{{fchanged}}”

- local_action: template src=checksums.j2 dest={{today_file}}

- local_action: file src={{today_file}} path=/checks/latest state=link

______________________ / Just until you setup \\ aide|osiris|tripwire / ---------------------- \ \ /\_)o< | \ | O . O| \_____/

#AUDIT>facts_drift

● set fact caching to use jsonfile

● make git repo or checkout in cache dir

● set incron to commit when file changes

● now git log shows facts change over time

● filter out time facts (or not)

● … so ... tower will do this for me?

#AUDIT>file_changes_xattr

● {{ansible_managed}} (changed or lack info)

● use xattr to keep metadata with the file

● requires user_xattr on mount

● great ETL, can keep correct file transforms

● does not affect copy/template ‘changed’

#HACK>expand_ansible

● roles: as shared libraries

● plugins: there are more than modules

● callbacks: send events

● notification modules: specific events

● dynamic modules: if you crave abstraction

#HACK>tidy# tidy_expected: [‘conf1.cfg’, conf2.cfg’]

- find: paths={{tidy_path}} #/etc/myapp

register: existing

- file: path={{item.path}} state=absent

when: item.path|basename not in tidy_expected

with_items: “{{existing.files|default([ ])}}”

register: removed

- mail: body=“{{removed}}”

#HACK>ansible_eventssyslog_json callback plugin

def __init__(self): self.logger = logging.getLogger('ansible logger') self.logger.setLevel(logging.DEBUG)

self.handler = logging.handlers.SysLogHandler( address = (os.getenv('SYSLOG_SERVER','locahost'), os.getenv('SYSLOG_PORT',514)), facility=logging.handlers.SysLogHandler.LOG_USER ) self.logger.addHandler(handler) ....

def runner_on_ok(self, host, res): self.logger.info('RUNNER_ON_OK ' + host + ' ' \

+ json.dumps(res, sort_keys=True))

def runner_on_skipped(self, host, item=None): self.logger.info('RUNNER_ON_SKIPPED ' + host)

#HACK>ansible_eventsosx_say callback plugin

def say(msg, voice): subprocess.call([SAY_CMD, msg, "--voice=%s" % (voice)])

def __init__(self):

# plugin disable itself if say is not present if not os.path.exists(SAY_CMD): self.disabled = True print "%s does not exist, plugin %s disabled" % \ (SAY_CMD, os.path.basename(__file__))

def runner_on_failed(self, host, res, ignore_errors=False): say("Failure on host %s" % host, FAILED_VOICE)

def runner_on_ok(self, host, res): say("pew", LASER_VOICE)

________________________________________________ / https://github.com/mpdehaan/ansible-and-juliet \\ / ------------------------------------------------ \ \ ,;;;;;;;, ;;;;;;;;;;;, ;;;;;'_____;' ;;;(/))))|((\ _;;((((((|)))) / |_\\\\\\\\\\\\ .--~( \ ~)))))))))))) / \ `\-(((((((((((\\ | | `\ ) |\ /|) | | `. _/ \_____/ | | , `\~ / | \ \ / | `. `\| / | ~- `\ / \____~._/~ -_, (\ |-----|\ \ ';; | | :;;;' \ | / | | | | |

#HACK>executing tasks- action:

module: <module name>

- action: <module name>

- <module name>:

● optionally ‘local_action’ instead of ‘action’

● module name as a variable {{mymodule}}

#HACK>abstract package- include_vars: “{{ansible_os_distribution|default(‘default’)}}.yml”

- name: install apache

action: “{{ansible_pkg_mgr}} name={{item}} state=present”

with_items: “{{apache_pkgs}}”

- template:

src: “{{apache_config}}.j2”

dest: /etc/{{apache_config}}

owner: “{{apache_user}}”

group: “{{apache_group}}”

notify: “apache_restart”

#HACK>abstract package

Redhat.yml

---

apache_user: httpd

apache_group: httpd

apache_config: /etc/httpd/conf/httpd.conf

apache_pkgs:

- httpd

- mod_ssl

- php-fpm

apache_service: httpd

#HACK>abstract package

Debian.yml

---

apache_user: www-data

apache_group: www-data

apache_config: /etc/apache2/httpd.conf

apache_pkgs:

- apache2-mpm

- libapache2-mod-ssl

- php5-fpm

apache_service: apache2

__________________ / can break \ \ apachectl utils / ------------------ \ \ .--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/

#THE END>wait 6 && exit

● Ansible was born to play well with Unix

● Roles allow for reuse and sharing

● Plugins are where you code

● Plugins are useful to non programmers.

● callbacks, lookups, filters, etc are also plugins

● Many ways to make Ansible work for you

__________ < goodbye! > ---------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||