Sunteți pe pagina 1din 26

Tips & Tricks

Not 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 ____________________


/ It runs a TASK * x \
\ on a HOST * x /
--------------------
● Automation framework \ ^__^
\ (oo)\_______
(__)\ )\/\
● Orchestration system ||----w |
|| ||

● Distributed batch executor


#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 200
48108 304
8550 302
6541 301
1696 404
269 206

web2 | success | rc=0 >>


205807 200
43762 304
...
#LIVE>procmail ______________
< you got mail >
--------------
\ , ,
\ /( )`
\ \ \___ / |
/- _ `-/ '
-- procmail (/\/ \ \ /\
/ / | ` \
:0 #send back http code live report O O ) /
`-^--'`<
|
'
(_.) _ ) /
* ^From.*@example.com `.___/`
`-----' /
/

<----. __ / __ \
* ^Subject:.*500 report <----|====O)))==) \) /====
<----' `--' `.__,' \
|ansible-playbook ~/plays/report.yml |
\
|
/
______( (_ / \______
,' ,-----' | \
`--{__________) \/

--- #report.yml

- shell: "awk '{print \$9}' …
register: report
- mail: to={{lookup(‘env’,’FROM’)}} body={{report}} …
#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?” / for reusability, use \
- name: app_version \ includes and roles /
prompt: “Choose version/tag (default HEAD)”
default: ‘HEAD’
----------------------
\
tasks: \ __
- git: repo=git@myreposerver/{{app_version}} version={{app_version}} ...
...
UooU\.'@@@@@@`.
\__/(@@@@@@@@@@)
- hosts: app_servers (@@@@@@@@)
serial: 1
tasks: `YY~~~~YY'
- 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 …
...
#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 ____________________________________
/ or if your playbook is idempotent, \
\ just run it again Sam! /
------------------------------------
- hosts: app_server \
\ \
tasks: \ /\
( )
- users: name=appuser state=present
.( o ).
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
#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}}” < or call nmap >
host: prod.example.com --------------
\
delegate_to: outside.host.com \
with_items: [‘80, ‘443’] ___
{~._.~}
( Y )
- 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
#AUDIT>check_file_changes
# from vars today_file: checks/{{inventory_hostname}}/{{today}}.txt
- find: paths=/etc recurse=Y size=1 age=1d ______________________
registered: fchanged / Just until you setup \
\ aide|osiris|tripwire /
- assert: ----------------------
that: \
\
- fchanged|length == 0
/\_)o<
| \
- assert: | O . O|
\_____/
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
#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_events
syslog_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_events
________________________________________________
/ https://github.com/mpdehaan/ansible-and-juliet \
osx_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)
#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 / can break \
\ apachectl utils /
------------------
\
\
--- .--.
apache_user: www-data |o_o |
|:_/ |
apache_group: www-data // \ \
(| | )
apache_config: /etc/apache2/httpd.conf /'\_ _/`\
\___)=(___/
apache_pkgs:
- apache2-mpm
- libapache2-mod-ssl
- php5-fpm
apache_service: apache2
#THE END>wait 6 && exit
● Ansible was born to play well with Unix
● Roles allow for reuse and sharing __________
< goodbye! >
----------
\ ^__^

● Plugins are where you code \ (oo)\_______


(__)\ )\/\
||----w |
|| ||

● Plugins are useful to non programmers.


● callbacks, lookups, filters, etc are also plugins
● Many ways to make Ansible work for you

S-ar putea să vă placă și