SlideShare a Scribd company logo
Hacking Ansible 
make it do more 
ansiblefest 10/2014
Who am I? 
programmer 
DBA 
system administrator 
tinkerer 
devops 
tech-janitor 
____________ 
< irc lurker > 
------------ 
 , , 
 /( )` 
  ___ / | 
/- _ `-/ ' 
(//   / 
/ / | `  
O O ) / | 
`-^--'`< ' 
(_.) _ ) / 
`.___/` / 
`-----' / 
<----. __ / __  
<----|====O)))==) ) /==== 
<----' `--' `.__,'  
| | 
 / 
______( (_ / ______ 
,' ,-----' |  
`--{__________) /
________________ 
/ It runs a TASK  
 on a HOST / 
---------------- 
 ^__^ 
 (oo)_______ 
(__) )/ 
||----w | 
|| || 
What is ansible? 
● Configuration management? 
● Automation platform? 
● Release management? 
● Orchestration system?
The Guts: ansible internal objects 
● inventory: defines my targets 
● runner: actually does the work 
● connection: how to get to my targets 
● playbook: all plays in current invocation 
○ play 
■ host: where to do it 
■ task: “it” aka “what to do” 
● callback: show me what was done
Example hack - the core 
--- a/lib/ansible/playbook/__init__.py 
+++ b/lib/ansible/playbook/__init__.py 
@@ -346,6 +346,8 @@ class PlayBook(object): 
run_hosts=hosts 
) 
+ runner.module_vars.update({'play_hosts': hosts}) 
+ 
if task.async_seconds == 0: 
results = runner.run() 
else:
Example hack - the core 
● 10 second patch to add play_hosts 
● 3h to find correct spot to patch 
● learned a lot about playbook/host iteration 
● I did not take “serial:” into account 
● runner rewrite in progress
The 
plugin 
system
PluginLoader 
... 
lookup_loader = PluginLoader( 
'LookupModule', 
'ansible.runner.lookup_plugins', 
C.DEFAULT_LOOKUP_PLUGIN_PATH, 
'lookup_plugins' 
) 
vars_loader = PluginLoader( 
'VarsModule', 
'ansible.inventory.vars_plugins', 
C.DEFAULT_VARS_PLUGIN_PATH, 
'vars_plugins' 
) 
lib/ansible/utils/plugins.py 
__________________ 
/ all plugins  
 except inventory / 
------------------ 
 ,__, 
 (oo)____ 
(__) ) 
||--|| *
Plugins 
● Library: host tasks/actions/modules 
● Action: master side tasks/actions/modules 
● Cache: fact caching 
● Callback: play output 
● Connection: host connections
Plugins 
● Shell: what shell to use to execute tasks 
● Lookup: master side info lookup 
● Vars: variable imports 
● Inventory: aside from inventory scripts 
● Filter: jinja2 filters for data modification 
● Doc Fragment: shared docs for library
Library/Action - May 2013 (72) 
add_host,debug,get_url,mount,postgresql_user,slurp,apt, 
django_manage,git,mysql_db,rabbitmq_parameter, 
subversion,apt_key,easy_install,group,mysql_user, 
rabbitmq_plugin,supervisorctl,apt_repository,ec2,group_by, 
nagios,rabbitmq_user,svr4pkg,assemble,ec2_facts,hg,ohai, 
rabbitmq_vhost,sysctl,async_status,ec2_vol,ini_file,opkg, 
raw,template,async_wrapper,facter,libr,pacman,script,uri, 
authorized_key,fail,lineinfile,pause,seboolean,user, 
cloudformation,fetch,lvol,ping,selinux,virt,command,file, 
macports,pip,service,wait_for,copy,fireball,mail,pkgin,setup, 
yum,cron,gem,mongodb_user,postgresql_db,shell,zfs
Library/Action - October 2014 (175) 
a10_server,a10_service_group,a10_virtual_server,accelerate,acl,add_host,airbrake_deployment,alternatives,apache2_module, 
apt,apt_key,apt_repository,apt_rpm,assemble,assert,async_status,at,authorized_key,azure,bigip_facts,bigip_monitor_http, 
bigip_monitor_tcp,bigip_node,bigip_pool,bigip_pool_member,bigpanda,boundary_meter,bzr,campfire,capabilities,cloudformation, 
command,composer,copy,cpanm,cron,datadog_event,debconf,debug,digital_ocean,digital_ocean_domain,digital_ocean_sshkey, 
django_manage,dnsimple,dnsmadeeasy,docker,docker_image,easy_install,ec2,ec2_ami,ec2_ami_search,ec2_asg,ec2_eip, 
ec2_elb,ec2_elb_lb,ec2_facts,ec2_group,ec2_key,ec2_lc,ec2_metric_alarm,ec2_scaling_policy,ec2_snapshot,ec2_tag,ec2_vol, 
ec2_vpc,ejabberd_user,elasticache,facter,fail,fetch,file,filesystem,fireball,firewalld,flowdock,gc_storage,gce,gce_lb,gce_net, 
gce_pd,gem,get_url,getent,git,github_hooks,glance_image,group,group_by,grove,hg,hipchat,homebrew,homebrew_cask, 
homebrew_tap,hostname,htpasswd,include_vars,ini_file,irc,jabber,jboss,jira,kernel_blacklist,keystone_user,layman, 
librato_annotation,lineinfile,linode,lldp,locale_gen,logentries,lvg,lvol,macports,mail,modprobe,mongodb_user,monit,mount,mqtt, 
mysql_db,mysql_replication,mysql_user,mysql_variables,nagios,netscaler,newrelic_deployment,nexmo,nova_compute, 
nova_keypair,npm,ohai,open_iscsi,openbsd_pkg,openvswitch_bridge,openvswitch_port,opkg,osx_say,ovirt,pacman,pagerduty, 
pause,ping,pingdom,pip,pkgin,pkgng,pkgutil,portage,portinstall,postgresql_db,postgresql_privs,postgresql_user, 
quantum_floating_ip,quantum_floating_ip_associate,quantum_network,quantum_router,quantum_router_gateway, 
quantum_router_interface,quantum_subnet,rabbitmq_parameter,rabbitmq_plugin,rabbitmq_policy,rabbitmq_user,rabbitmq_vhost, 
raw,rax,rax_cbs,rax_cbs_attachments,rax_cdb,rax_cdb_database,rax_cdb_user,rax_clb,rax_clb_nodes,rax_dns,rax_dns_record, 
rax_facts,rax_files,rax_files_objects,rax_identity,rax_keypair,rax_meta,rax_network,rax_queue,rax_scaling_group, 
rax_scaling_policy,rds,rds_param_group,rds_subnet_group,redhat_subscription,redis,replace,rhn_channel,rhn_register,riak, 
rollbar_deployment,route53,rpm_key,s3,script,seboolean,selinux,service,set_fact,setup,shell,slack,slurp,sns,stackdriver,stat, 
subversion,supervisorctl,svr4pkg,swdepot,synchronize,sysctl,template,twilio,typetalk,ufw,unarchive,uri,urpmi,user,virt, 
vsphere_guest,wait_for,win_feature,win_get_url,win_group,win_msi,win_ping,win_service,win_stat,win_user,xattr,yum, 
zabbix_maintenance,zfs,zypper,zypper_repository
Filters: Jinja2’ism 
● best way to change data 
● chainable pipes 
● simple to expand 
● can hide complexity 
__________________________ 
< [hello, world]|join(‘ ‘) > 
-------------------------- 
 ^__^ 
 (oo)_______ 
(__) )/ 
||----w | 
|| ||
Example hack - filter 
import random 
def randomize_list(mylist): 
random.shuffle(mylist) 
return mylist 
... 
def filters(self): # this maps filter names to functions 
return { 
‘shuffle’: randomize_list, 
... 
} 
lib/ansible/runner/filter_plugins/core.py
Example hack - filter 
- hosts: all 
connection: local 
gather_facts: false 
vars: 
- mylist: [1,2,3,4,5] 
tasks: 
- debug: msg=”{{item}}” 
with_items: “{{mylist|shuffle}}”
Example hack - filter 
#>ansible-playbook test.yml -i ‘localhost,’ 
__________________________ 
< TASK: debug msg={{item}} > 
-------------------------- 
ok: [localhost] => (item=1) => { 
"item": 1, 
"msg": "1" 
} 
ok: [localhost] => (item=3) => { 
"item": 3, 
"msg": "3" 
} 
ok: [localhost] => (item=4) => { 
"item": 4, 
"msg": "4" 
} 
ok: [localhost] => (item=5) => { 
"item": 5, 
"msg": "5" 
} 
ok: [localhost] => (item=2) => { 
"item": 2, 
"msg": "2" 
} 
__________________________ 
< TASK: debug msg={{item}} > 
-------------------------- 
ok: [localhost] => (item=3) => { 
"item": 3, 
"msg": "3" 
} 
ok: [localhost] => (item=2) => { 
"item": 2, 
"msg": "2" 
} 
ok: [localhost] => (item=5) => { 
"item": 5, 
"msg": "5" 
} 
ok: [localhost] => (item=2) => { 
"item": 2, 
"msg": "2" 
} 
ok: [localhost] => (item=1) => { 
"item": 1, 
"msg": "1" 
} 
__________________________ 
< TASK: debug msg={{item}} > 
-------------------------- 
ok: [localhost] => (item=2) => { 
"item": 2, 
"msg": "2" 
} 
ok: [localhost] => (item=4) => { 
"item": 4, 
"msg": "4" 
} 
ok: [localhost] => (item=1) => { 
"item": 1, 
"msg": "1" 
} 
ok: [localhost] => (item=3) => { 
"item": 3, 
"msg": "3" 
} 
ok: [localhost] => (item=5) => { 
"item": 5, 
"msg": "5" 
}
Lookups 
● you are already using them: with_<lookup> 
● they execute on the “master” 
● a way to access external files and/or data 
● normally returns a list
Example hack - lookup 
lib/ansible/runner/lookup_plugins/etcd.py 
class LookupModule(object): 
def __init__(self, basedir=None, **kwargs): 
self.basedir = basedir 
self.etcd = etcd() # initializes etcd class 
def run(self, terms, inject=None, **kwargs): 
terms = utils.listify_lookup_plugin_terms(terms, self.basedir, inject) 
if isinstance(terms, basestring): 
terms = [ terms ] 
ret = [] 
for term in terms: 
key = term.split()[0] 
value = self.etcd.get(key) # gets the data from etcd class 
ret.append(value) 
return ret
Example hack - lookup 
lib/ansible/runner/lookup_plugins/etcd.py 
class etcd(): # simplified version 
def __init__(self, url=ANSIBLE_ETCD_URL): 
self.url = url 
self.baseurl = '%s/v1/keys' % (self.url) 
def get(self, key): 
url = "%s/%s" % (self.baseurl, key) 
r = urllib2.urlopen(url) 
data = r.read() 
item = json.loads(data) 
value = item['value'] 
return value 
_______________ 
/ written by  
 Jan-Piet Mens / 
--------------- 
 ,__, 
 (oo)____ 
(__) ) 
||--|| *
Example hack - lookup 
#>ansible all -m debug -a ‘msg={{lookup(“etcd”,”key1”)}}’ -i ‘localhost,’ 
localhost | success >> { 
"msg": "value1" 
} 
#>ansible all -m debug -a ‘msg={{lookup(“etcd”,”key2”)}}’ -i ‘localhost,’ 
localhost | success >> { 
"msg": "value2" 
}
Example hack - callback 
callback_plugins/profile_tasks.py 
class CallbackModule(object): # simplified example 
def playbook_on_task_start(self, name, is_conditional): 
_______________ 
/ written by  
 Jharrod LaFon / 
--------------- 
 ,__, 
 (oo)____ 
if self.current is not None: # Record the total time of the previous 
self.stats[self.current] = time.time() - self.stats[self.current] 
self.current = name # Record the start time of the current task 
self.stats[self.current] = time.time() 
def playbook_on_stats(self, stats): # Sort the tasks by their running time 
... 
(__) ) 
||--|| * 
results = sorted(self.stats.items(), key=lambda value: value[1], reverse=True) 
for name, elapsed in results: # Print the timings 
print "{0:-<70}{1:->9}".format('{0} '.format(name),'{0:.02f}s'.format(elapsed))
Example hack - callback 
#>ansible-playbook test.yml -i ‘localhost,’ 
# re-running the previous filter/shuffle playbook 
__________________________ 
< TASK: debug msg={{item}} > 
-------------------------- 
ok: [localhost] => (item=2) => { 
"item": 2, 
"msg": "2" 
} 
... 
ok: [localhost] => (item=4) => { 
"item": 4, 
"msg": "4" 
} 
PLAY RECAP ******************************************************************** 
debug msg={{item}} ------------------------------------------------------ 0.02s 
localhost : ok=1 changed=0 unreachable=0 failed=0
Example hack - cache 
import exceptions 
class BaseCacheModule(object): 
def get(self, key): 
lib/ansible/cache/base.py 
raise exceptions.NotImplementedError 
def set(self, key, value): 
raise exceptions.NotImplementedError 
def keys(self): 
raise exceptions.NotImplementedError 
def contains(self, key): 
raise exceptions.NotImplementedError 
def delete(self, key): 
raise exceptions.NotImplementedError 
def flush(self): 
raise exceptions.NotImplementedError 
def copy(self): 
raise exceptions.NotImplementedError 
________________ 
/ I abandoned it  
| and Josh Drake | 
 revived it / 
---------------- 
 / ___ / 
 // / /  
(( O O )) 
 /  // 
/ | | / 
| | | | 
| | | | 
| o | 
| | | | 
|m| |m|
Example hack - cache 
from ansible.cache.base import BaseCacheModule 
class CacheModule(BaseCacheModule): 
def __init__(self, *args, **kwargs): 
self._cache = {} 
def get(self, key): 
return self._cache.get(key) 
def set(self, key, value): 
self._cache[key] = value 
def keys(self): 
return self._cache.keys() 
def contains(self, key): 
return key in self._cache 
def delete(self, key): 
del self._cache[key] 
def flush(self): 
lib/ansible/cache/memory.py
Example hack - cache 
from redis import StrictRedis 
class CacheModule(BaseCacheModule): # simplified version 
self._cache = StrictRedis(*connection) 
... 
def get(self, key): 
value = self._cache.get(self._make_key(key))# make_key creates correct prefix 
# guard against the key not being removed from the zset 
if value is None: 
self.delete(key) 
raise KeyError 
return json.loads(value) 
def set(self, key, value): 
value2 = json.dumps(value) 
if self._timeout > 0: # a timeout of 0 is handled as meaning 'never expire' 
self._cache.setex(self._make_key(key), int(self._timeout), value2) 
else: 
self._cache.set(self._make_key(key), value2) 
self._cache.zadd(self._keys_set, time.time(), key) 
... 
lib/ansible/cache/redis.py
Tests: test/ 
● sadly the presenter sucks at test coverage 
● no really, tests are good, regressions! 
● assert: the test module 
● destructive, non destructive, integration 
● ‘make tests’, runs unit tests
Before you submit 
● update documentation (it is also in the repo) 
● create tests, assert! (also in the repo) 
● prepare a clear usage/example to post in the PR 
● its a dialog, be ready to make your ‘use case’ 
● patience … … … … 
● not everything belongs in core

More Related Content

PDF
Get Mainframe Visibility to Enhance SIEM Efforts in Splunk
PDF
Event driven autoscaling with keda
PDF
Elasticsearch in Netflix
PDF
[215] Druid로 쉽고 빠르게 데이터 분석하기
PPTX
Helm - Package manager in K8S
PDF
GitOps with Gitkube
PPTX
Thrift vs Protocol Buffers vs Avro - Biased Comparison
PDF
OpenShift Multicluster
Get Mainframe Visibility to Enhance SIEM Efforts in Splunk
Event driven autoscaling with keda
Elasticsearch in Netflix
[215] Druid로 쉽고 빠르게 데이터 분석하기
Helm - Package manager in K8S
GitOps with Gitkube
Thrift vs Protocol Buffers vs Avro - Biased Comparison
OpenShift Multicluster

What's hot (20)

PPSX
Event Sourcing & CQRS, Kafka, Rabbit MQ
PDF
Modern Tools for API Testing, Debugging and Monitoring
PDF
Real-time Data Streaming from Oracle to Apache Kafka
PDF
Elastic Observability
PDF
How Uber scaled its Real Time Infrastructure to Trillion events per day
PPT
Data-Centric and Message-Centric System Architecture
PPTX
【Unite 2017 Tokyo】マルチプレイゲームのグローバル展開事例(BNE様)と完全同期を実現するPhoton TrueSync のご紹介
PDF
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
PDF
ゲーム開発を加速させる クライアントセキュリティ
PDF
Cloud-Native Observability
PPTX
Unified Batch & Stream Processing with Apache Samza
PDF
Modern Application Configuration in Kubernetes
PDF
Kafka Connect & Streams - the ecosystem around Kafka
PDF
Splunk Data Onboarding Overview - Splunk Data Collection Architecture
PPTX
RocksDB compaction
PDF
猿でもわかる Helm
PPTX
Kafka replication apachecon_2013
PDF
Consumer offset management in Kafka
PDF
Scapyで作る・解析するパケット
PDF
How Netflix Tunes EC2 Instances for Performance
Event Sourcing & CQRS, Kafka, Rabbit MQ
Modern Tools for API Testing, Debugging and Monitoring
Real-time Data Streaming from Oracle to Apache Kafka
Elastic Observability
How Uber scaled its Real Time Infrastructure to Trillion events per day
Data-Centric and Message-Centric System Architecture
【Unite 2017 Tokyo】マルチプレイゲームのグローバル展開事例(BNE様)と完全同期を実現するPhoton TrueSync のご紹介
Schema Registry 101 with Bill Bejeck | Kafka Summit London 2022
ゲーム開発を加速させる クライアントセキュリティ
Cloud-Native Observability
Unified Batch & Stream Processing with Apache Samza
Modern Application Configuration in Kubernetes
Kafka Connect & Streams - the ecosystem around Kafka
Splunk Data Onboarding Overview - Splunk Data Collection Architecture
RocksDB compaction
猿でもわかる Helm
Kafka replication apachecon_2013
Consumer offset management in Kafka
Scapyで作る・解析するパケット
How Netflix Tunes EC2 Instances for Performance

Viewers also liked (16)

PDF
What's New in v2 - AnsibleFest London 2015
PPT
Ansible presentation
PDF
Ansible tips & tricks
PDF
Ansible leveraging 2.0
PDF
More tips n tricks
PPTX
Ansible module development 101
PPTX
How to Automate Big Data with Ansible
PDF
Achieving Continuous Delivery: An Automation Story
PDF
AnsibleFest 2014 - Role Tips and Tricks
PDF
Automated Security Hardening with OpenStack-Ansible
PDF
Debugging ansible modules
PPT
Local Dev on Virtual Machines - Vagrant, VirtualBox and Ansible
PPTX
HP Advanced Technology Group: Docker and Ansible
PPTX
Automated Deployments with Ansible
PDF
Ansible - Swiss Army Knife Orchestration
PDF
V2 and beyond
What's New in v2 - AnsibleFest London 2015
Ansible presentation
Ansible tips & tricks
Ansible leveraging 2.0
More tips n tricks
Ansible module development 101
How to Automate Big Data with Ansible
Achieving Continuous Delivery: An Automation Story
AnsibleFest 2014 - Role Tips and Tricks
Automated Security Hardening with OpenStack-Ansible
Debugging ansible modules
Local Dev on Virtual Machines - Vagrant, VirtualBox and Ansible
HP Advanced Technology Group: Docker and Ansible
Automated Deployments with Ansible
Ansible - Swiss Army Knife Orchestration
V2 and beyond

Similar to Hacking ansible (20)

PPTX
Ansible for Beginners
PDF
Ansible for beginners ...?
PDF
Ansible101
PDF
Network Automation: Ansible 102
PDF
Ansible - Introduction
PDF
Writing Ansible Modules (CLT'19)
PPTX
Best practices for ansible
PPTX
Intro to-ansible-sep7-meetup
PDF
Writing Ansible Modules (DENOG11)
PDF
Managing PostgreSQL with Ansible - FOSDEM PGDay 2016
PDF
DevOpsDaysCPT Ansible Infrastrucutre as Code 2017
PDF
Ansible is the simplest way to automate. SymfonyCafe, 2015
PDF
Network Automation: Ansible 101
PDF
Ansible not only for Dummies
PDF
Automating with ansible (Part c)
PDF
Getting Started with Ansible
PDF
Ansible - Hands on Training
PDF
Ansible
PDF
Ansible Tutorial.pdf
PDF
Getting Started with Ansible - Jake.pdf
Ansible for Beginners
Ansible for beginners ...?
Ansible101
Network Automation: Ansible 102
Ansible - Introduction
Writing Ansible Modules (CLT'19)
Best practices for ansible
Intro to-ansible-sep7-meetup
Writing Ansible Modules (DENOG11)
Managing PostgreSQL with Ansible - FOSDEM PGDay 2016
DevOpsDaysCPT Ansible Infrastrucutre as Code 2017
Ansible is the simplest way to automate. SymfonyCafe, 2015
Network Automation: Ansible 101
Ansible not only for Dummies
Automating with ansible (Part c)
Getting Started with Ansible
Ansible - Hands on Training
Ansible
Ansible Tutorial.pdf
Getting Started with Ansible - Jake.pdf

Recently uploaded (20)

PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Advanced IT Governance
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
GDG Cloud Iasi [PUBLIC] Florian Blaga - Unveiling the Evolution of Cybersecur...
PPTX
breach-and-attack-simulation-cybersecurity-india-chennai-defenderrabbit-2025....
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Modernizing your data center with Dell and AMD
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Advanced Soft Computing BINUS July 2025.pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PPT
Teaching material agriculture food technology
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Advanced IT Governance
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
GDG Cloud Iasi [PUBLIC] Florian Blaga - Unveiling the Evolution of Cybersecur...
breach-and-attack-simulation-cybersecurity-india-chennai-defenderrabbit-2025....
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Chapter 3 Spatial Domain Image Processing.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Per capita expenditure prediction using model stacking based on satellite ima...
Modernizing your data center with Dell and AMD
Understanding_Digital_Forensics_Presentation.pptx
NewMind AI Weekly Chronicles - August'25 Week I
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Network Security Unit 5.pdf for BCA BBA.
Advanced Soft Computing BINUS July 2025.pdf
Advanced methodologies resolving dimensionality complications for autism neur...
Teaching material agriculture food technology

Hacking ansible

  • 1. Hacking Ansible make it do more ansiblefest 10/2014
  • 2. Who am I? programmer DBA system administrator tinkerer devops tech-janitor ____________ < irc lurker > ------------ , , /( )` ___ / | /- _ `-/ ' (// / / / | ` O O ) / | `-^--'`< ' (_.) _ ) / `.___/` / `-----' / <----. __ / __ <----|====O)))==) ) /==== <----' `--' `.__,' | | / ______( (_ / ______ ,' ,-----' | `--{__________) /
  • 3. ________________ / It runs a TASK on a HOST / ---------------- ^__^ (oo)_______ (__) )/ ||----w | || || What is ansible? ● Configuration management? ● Automation platform? ● Release management? ● Orchestration system?
  • 4. The Guts: ansible internal objects ● inventory: defines my targets ● runner: actually does the work ● connection: how to get to my targets ● playbook: all plays in current invocation ○ play ■ host: where to do it ■ task: “it” aka “what to do” ● callback: show me what was done
  • 5. Example hack - the core --- a/lib/ansible/playbook/__init__.py +++ b/lib/ansible/playbook/__init__.py @@ -346,6 +346,8 @@ class PlayBook(object): run_hosts=hosts ) + runner.module_vars.update({'play_hosts': hosts}) + if task.async_seconds == 0: results = runner.run() else:
  • 6. Example hack - the core ● 10 second patch to add play_hosts ● 3h to find correct spot to patch ● learned a lot about playbook/host iteration ● I did not take “serial:” into account ● runner rewrite in progress
  • 8. PluginLoader ... lookup_loader = PluginLoader( 'LookupModule', 'ansible.runner.lookup_plugins', C.DEFAULT_LOOKUP_PLUGIN_PATH, 'lookup_plugins' ) vars_loader = PluginLoader( 'VarsModule', 'ansible.inventory.vars_plugins', C.DEFAULT_VARS_PLUGIN_PATH, 'vars_plugins' ) lib/ansible/utils/plugins.py __________________ / all plugins except inventory / ------------------ ,__, (oo)____ (__) ) ||--|| *
  • 9. Plugins ● Library: host tasks/actions/modules ● Action: master side tasks/actions/modules ● Cache: fact caching ● Callback: play output ● Connection: host connections
  • 10. Plugins ● Shell: what shell to use to execute tasks ● Lookup: master side info lookup ● Vars: variable imports ● Inventory: aside from inventory scripts ● Filter: jinja2 filters for data modification ● Doc Fragment: shared docs for library
  • 11. Library/Action - May 2013 (72) add_host,debug,get_url,mount,postgresql_user,slurp,apt, django_manage,git,mysql_db,rabbitmq_parameter, subversion,apt_key,easy_install,group,mysql_user, rabbitmq_plugin,supervisorctl,apt_repository,ec2,group_by, nagios,rabbitmq_user,svr4pkg,assemble,ec2_facts,hg,ohai, rabbitmq_vhost,sysctl,async_status,ec2_vol,ini_file,opkg, raw,template,async_wrapper,facter,libr,pacman,script,uri, authorized_key,fail,lineinfile,pause,seboolean,user, cloudformation,fetch,lvol,ping,selinux,virt,command,file, macports,pip,service,wait_for,copy,fireball,mail,pkgin,setup, yum,cron,gem,mongodb_user,postgresql_db,shell,zfs
  • 12. Library/Action - October 2014 (175) a10_server,a10_service_group,a10_virtual_server,accelerate,acl,add_host,airbrake_deployment,alternatives,apache2_module, apt,apt_key,apt_repository,apt_rpm,assemble,assert,async_status,at,authorized_key,azure,bigip_facts,bigip_monitor_http, bigip_monitor_tcp,bigip_node,bigip_pool,bigip_pool_member,bigpanda,boundary_meter,bzr,campfire,capabilities,cloudformation, command,composer,copy,cpanm,cron,datadog_event,debconf,debug,digital_ocean,digital_ocean_domain,digital_ocean_sshkey, django_manage,dnsimple,dnsmadeeasy,docker,docker_image,easy_install,ec2,ec2_ami,ec2_ami_search,ec2_asg,ec2_eip, ec2_elb,ec2_elb_lb,ec2_facts,ec2_group,ec2_key,ec2_lc,ec2_metric_alarm,ec2_scaling_policy,ec2_snapshot,ec2_tag,ec2_vol, ec2_vpc,ejabberd_user,elasticache,facter,fail,fetch,file,filesystem,fireball,firewalld,flowdock,gc_storage,gce,gce_lb,gce_net, gce_pd,gem,get_url,getent,git,github_hooks,glance_image,group,group_by,grove,hg,hipchat,homebrew,homebrew_cask, homebrew_tap,hostname,htpasswd,include_vars,ini_file,irc,jabber,jboss,jira,kernel_blacklist,keystone_user,layman, librato_annotation,lineinfile,linode,lldp,locale_gen,logentries,lvg,lvol,macports,mail,modprobe,mongodb_user,monit,mount,mqtt, mysql_db,mysql_replication,mysql_user,mysql_variables,nagios,netscaler,newrelic_deployment,nexmo,nova_compute, nova_keypair,npm,ohai,open_iscsi,openbsd_pkg,openvswitch_bridge,openvswitch_port,opkg,osx_say,ovirt,pacman,pagerduty, pause,ping,pingdom,pip,pkgin,pkgng,pkgutil,portage,portinstall,postgresql_db,postgresql_privs,postgresql_user, quantum_floating_ip,quantum_floating_ip_associate,quantum_network,quantum_router,quantum_router_gateway, quantum_router_interface,quantum_subnet,rabbitmq_parameter,rabbitmq_plugin,rabbitmq_policy,rabbitmq_user,rabbitmq_vhost, raw,rax,rax_cbs,rax_cbs_attachments,rax_cdb,rax_cdb_database,rax_cdb_user,rax_clb,rax_clb_nodes,rax_dns,rax_dns_record, rax_facts,rax_files,rax_files_objects,rax_identity,rax_keypair,rax_meta,rax_network,rax_queue,rax_scaling_group, rax_scaling_policy,rds,rds_param_group,rds_subnet_group,redhat_subscription,redis,replace,rhn_channel,rhn_register,riak, rollbar_deployment,route53,rpm_key,s3,script,seboolean,selinux,service,set_fact,setup,shell,slack,slurp,sns,stackdriver,stat, subversion,supervisorctl,svr4pkg,swdepot,synchronize,sysctl,template,twilio,typetalk,ufw,unarchive,uri,urpmi,user,virt, vsphere_guest,wait_for,win_feature,win_get_url,win_group,win_msi,win_ping,win_service,win_stat,win_user,xattr,yum, zabbix_maintenance,zfs,zypper,zypper_repository
  • 13. Filters: Jinja2’ism ● best way to change data ● chainable pipes ● simple to expand ● can hide complexity __________________________ < [hello, world]|join(‘ ‘) > -------------------------- ^__^ (oo)_______ (__) )/ ||----w | || ||
  • 14. Example hack - filter import random def randomize_list(mylist): random.shuffle(mylist) return mylist ... def filters(self): # this maps filter names to functions return { ‘shuffle’: randomize_list, ... } lib/ansible/runner/filter_plugins/core.py
  • 15. Example hack - filter - hosts: all connection: local gather_facts: false vars: - mylist: [1,2,3,4,5] tasks: - debug: msg=”{{item}}” with_items: “{{mylist|shuffle}}”
  • 16. Example hack - filter #>ansible-playbook test.yml -i ‘localhost,’ __________________________ < TASK: debug msg={{item}} > -------------------------- ok: [localhost] => (item=1) => { "item": 1, "msg": "1" } ok: [localhost] => (item=3) => { "item": 3, "msg": "3" } ok: [localhost] => (item=4) => { "item": 4, "msg": "4" } ok: [localhost] => (item=5) => { "item": 5, "msg": "5" } ok: [localhost] => (item=2) => { "item": 2, "msg": "2" } __________________________ < TASK: debug msg={{item}} > -------------------------- ok: [localhost] => (item=3) => { "item": 3, "msg": "3" } ok: [localhost] => (item=2) => { "item": 2, "msg": "2" } ok: [localhost] => (item=5) => { "item": 5, "msg": "5" } ok: [localhost] => (item=2) => { "item": 2, "msg": "2" } ok: [localhost] => (item=1) => { "item": 1, "msg": "1" } __________________________ < TASK: debug msg={{item}} > -------------------------- ok: [localhost] => (item=2) => { "item": 2, "msg": "2" } ok: [localhost] => (item=4) => { "item": 4, "msg": "4" } ok: [localhost] => (item=1) => { "item": 1, "msg": "1" } ok: [localhost] => (item=3) => { "item": 3, "msg": "3" } ok: [localhost] => (item=5) => { "item": 5, "msg": "5" }
  • 17. Lookups ● you are already using them: with_<lookup> ● they execute on the “master” ● a way to access external files and/or data ● normally returns a list
  • 18. Example hack - lookup lib/ansible/runner/lookup_plugins/etcd.py class LookupModule(object): def __init__(self, basedir=None, **kwargs): self.basedir = basedir self.etcd = etcd() # initializes etcd class def run(self, terms, inject=None, **kwargs): terms = utils.listify_lookup_plugin_terms(terms, self.basedir, inject) if isinstance(terms, basestring): terms = [ terms ] ret = [] for term in terms: key = term.split()[0] value = self.etcd.get(key) # gets the data from etcd class ret.append(value) return ret
  • 19. Example hack - lookup lib/ansible/runner/lookup_plugins/etcd.py class etcd(): # simplified version def __init__(self, url=ANSIBLE_ETCD_URL): self.url = url self.baseurl = '%s/v1/keys' % (self.url) def get(self, key): url = "%s/%s" % (self.baseurl, key) r = urllib2.urlopen(url) data = r.read() item = json.loads(data) value = item['value'] return value _______________ / written by Jan-Piet Mens / --------------- ,__, (oo)____ (__) ) ||--|| *
  • 20. Example hack - lookup #>ansible all -m debug -a ‘msg={{lookup(“etcd”,”key1”)}}’ -i ‘localhost,’ localhost | success >> { "msg": "value1" } #>ansible all -m debug -a ‘msg={{lookup(“etcd”,”key2”)}}’ -i ‘localhost,’ localhost | success >> { "msg": "value2" }
  • 21. Example hack - callback callback_plugins/profile_tasks.py class CallbackModule(object): # simplified example def playbook_on_task_start(self, name, is_conditional): _______________ / written by Jharrod LaFon / --------------- ,__, (oo)____ if self.current is not None: # Record the total time of the previous self.stats[self.current] = time.time() - self.stats[self.current] self.current = name # Record the start time of the current task self.stats[self.current] = time.time() def playbook_on_stats(self, stats): # Sort the tasks by their running time ... (__) ) ||--|| * results = sorted(self.stats.items(), key=lambda value: value[1], reverse=True) for name, elapsed in results: # Print the timings print "{0:-<70}{1:->9}".format('{0} '.format(name),'{0:.02f}s'.format(elapsed))
  • 22. Example hack - callback #>ansible-playbook test.yml -i ‘localhost,’ # re-running the previous filter/shuffle playbook __________________________ < TASK: debug msg={{item}} > -------------------------- ok: [localhost] => (item=2) => { "item": 2, "msg": "2" } ... ok: [localhost] => (item=4) => { "item": 4, "msg": "4" } PLAY RECAP ******************************************************************** debug msg={{item}} ------------------------------------------------------ 0.02s localhost : ok=1 changed=0 unreachable=0 failed=0
  • 23. Example hack - cache import exceptions class BaseCacheModule(object): def get(self, key): lib/ansible/cache/base.py raise exceptions.NotImplementedError def set(self, key, value): raise exceptions.NotImplementedError def keys(self): raise exceptions.NotImplementedError def contains(self, key): raise exceptions.NotImplementedError def delete(self, key): raise exceptions.NotImplementedError def flush(self): raise exceptions.NotImplementedError def copy(self): raise exceptions.NotImplementedError ________________ / I abandoned it | and Josh Drake | revived it / ---------------- / ___ / // / / (( O O )) / // / | | / | | | | | | | | | o | | | | | |m| |m|
  • 24. Example hack - cache from ansible.cache.base import BaseCacheModule class CacheModule(BaseCacheModule): def __init__(self, *args, **kwargs): self._cache = {} def get(self, key): return self._cache.get(key) def set(self, key, value): self._cache[key] = value def keys(self): return self._cache.keys() def contains(self, key): return key in self._cache def delete(self, key): del self._cache[key] def flush(self): lib/ansible/cache/memory.py
  • 25. Example hack - cache from redis import StrictRedis class CacheModule(BaseCacheModule): # simplified version self._cache = StrictRedis(*connection) ... def get(self, key): value = self._cache.get(self._make_key(key))# make_key creates correct prefix # guard against the key not being removed from the zset if value is None: self.delete(key) raise KeyError return json.loads(value) def set(self, key, value): value2 = json.dumps(value) if self._timeout > 0: # a timeout of 0 is handled as meaning 'never expire' self._cache.setex(self._make_key(key), int(self._timeout), value2) else: self._cache.set(self._make_key(key), value2) self._cache.zadd(self._keys_set, time.time(), key) ... lib/ansible/cache/redis.py
  • 26. Tests: test/ ● sadly the presenter sucks at test coverage ● no really, tests are good, regressions! ● assert: the test module ● destructive, non destructive, integration ● ‘make tests’, runs unit tests
  • 27. Before you submit ● update documentation (it is also in the repo) ● create tests, assert! (also in the repo) ● prepare a clear usage/example to post in the PR ● its a dialog, be ready to make your ‘use case’ ● patience … … … … ● not everything belongs in core