SlideShare a Scribd company logo
1 of 66
Download to read offline
BATOU
multi-(component¦host¦environment¦.*)
deployment
Wednesday, 3.July 13
@theuni
Wednesday, 3.July 13
Wednesday, 3.July 13
Wednesday, 3.July 13
Wednesday, 3.July 13
AUTOMATING
DEPLOYMENTS IS
HARD
Wednesday, 3.July 13
HOW DOES
CONVERGENCE HELP?
Wednesday, 3.July 13
HOW DOES THIS
WORK WITH BATOU?
Wednesday, 3.July 13
SOME PERSPECTIVE
Wednesday, 3.July 13
Wednesday, 3.July 13
IT'S NOT THAT BAD.
Wednesday, 3.July 13
Wednesday, 3.July 13
service
deployment
Fabric,
Capistrano, ...
system
configuration
Puppet, Chef, ...
provisioning
kickstart, Razor,
imaging ...
Wednesday, 3.July 13
FTP
bash
mkzopeinstance
zc.buildout
fabric
Wednesday, 3.July 13
CONVERGENCE
Wednesday, 3.July 13
"Everything that follows is a
result of what you see here."
(Dr. Alfred Lanning; I, Robot)
Wednesday, 3.July 13
SIMPLE
os.mkdir('foo')
with open('foo/bar', 'w') as myfile:
myfile.write('asdf')
os.chmod('foo/bar', 0755)
Wednesday, 3.July 13
•unexpected system state
•can't resume
•unnecessary updates
os.mkdir('foo')
with open('foo/bar', 'w') as myfile:
myfile.write('asdf')
os.chmod('foo/bar', 0755)
SIMPLISTIC
Wednesday, 3.July 13
CORRECT(?)
if not os.path.isdir('foo'): os.unlink('foo')
if not os.path.exists('foo'): os.mkdir('foo')
try:
os.lstat('foo/bar')
except OSError: pass
else:
if os.path.isdir('foo/bar'):
shutil.rmtree('foo/bar')
else:
os.unlink('foo/bar')
if (os.path.exists('foo/bar') and
open('foo/bar', 'r').read() != 'asdf'):
open('foo/bar', 'w').write('asdf'):
current = os.stat('foo/bar').st_mode
if stat.S_IMODE(current) != 0755:
os.chmod('foo', 0755)
Wednesday, 3.July 13
SIMPLE
File('foo/bar',
content='asdf',
mode=0755,
leading=True)
Wednesday, 3.July 13
class File(Component):
namevar = 'path'
def configure(self):
self += Presence(
self.path, leading=self.leading)
self += Mode(self.path, self.mode)
self += Content(self.path, self.content)
File('foo/bar',
content='asdf',
mode=0755,
leading=True)
Wednesday, 3.July 13
class File(Component):
namevar = 'path'
def configure(self):
self += Presence(
self.path, leading=self.leading)
self += Mode(self.path, self.mode)
self += Content(self.path, self.content)
File('foo/bar',
content='asdf',
mode=0755,
leading=True)
compute target state
(no touching!)
Wednesday, 3.July 13
class File(Component):
namevar = 'path'
def configure(self):
self += Presence(
self.path, leading=self.leading)
self += Mode(self.path, self.mode)
self += Content(self.path, self.content)
File('foo/bar',
content='asdf',
mode=0755,
leading=True)
compute target state
(no touching!)
composition operator
Wednesday, 3.July 13
class File(Component):
namevar = 'path'
def configure(self):
self += Presence(
self.path, leading=self.leading)
self += Mode(self.path, self.mode)
self += Content(self.path, self.content)
File('foo/bar',
content='asdf',
mode=0755,
leading=True)
compute target state
(no touching!)
composition operator
order
matters
Wednesday, 3.July 13
class Presence(Component):
namevar = 'path'
leading = False
def configure(self):
if self.leading:
self += Directory(
os.path.dirname(self.path),
leading=self.leading)
def verify(self):
if not os.path.isfile(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
with open(self.path, 'w'):
pass
Wednesday, 3.July 13
class Presence(Component):
namevar = 'path'
leading = False
def configure(self):
if self.leading:
self += Directory(
os.path.dirname(self.path),
leading=self.leading)
def verify(self):
if not os.path.isfile(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
with open(self.path, 'w'):
pass
run "anywhere"
Wednesday, 3.July 13
class Presence(Component):
namevar = 'path'
leading = False
def configure(self):
if self.leading:
self += Directory(
os.path.dirname(self.path),
leading=self.leading)
def verify(self):
if not os.path.isfile(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
with open(self.path, 'w'):
pass
run on target
run "anywhere"
Wednesday, 3.July 13
class Presence(Component):
namevar = 'path'
leading = False
def configure(self):
if self.leading:
self += Directory(
os.path.dirname(self.path),
leading=self.leading)
def verify(self):
if not os.path.isfile(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
with open(self.path, 'w'):
pass
run on target
run "anywhere"
after all sub-
components
Wednesday, 3.July 13
class Presence(Component):
namevar = 'path'
leading = False
def configure(self):
if self.leading:
self += Directory(
os.path.dirname(self.path),
leading=self.leading)
def verify(self):
if not os.path.isfile(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
with open(self.path, 'w'):
pass
run on target
only if needed
run "anywhere"
after all sub-
components
Wednesday, 3.July 13
class Presence(Component):
namevar = 'path'
leading = False
def configure(self):
if self.leading:
self += Directory(
os.path.dirname(self.path),
leading=self.leading)
def verify(self):
if not os.path.isfile(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
with open(self.path, 'w'):
pass
run on target
only if needed
run "anywhere"
after all sub-
components
keep
delegating!
Wednesday, 3.July 13
class Directory(Component):
namevar = 'path'
leading = False
def verify(self):
if not os.path.isdir(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
if self.leading:
os.makedirs(self.path)
else:
os.mkdir(self.path)
Wednesday, 3.July 13
class Directory(Component):
namevar = 'path'
leading = False
def verify(self):
if not os.path.isdir(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
if self.leading:
os.makedirs(self.path)
else:
os.mkdir(self.path)
could be done with
recursive
composition
Wednesday, 3.July 13
class Directory(Component):
namevar = 'path'
leading = False
def verify(self):
if not os.path.isdir(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
if self.leading:
os.makedirs(self.path)
else:
os.mkdir(self.path)
could be done with
recursive
composition
refactor with
sub-components if too
complex
Wednesday, 3.July 13
class Directory(Component):
namevar = 'path'
leading = False
def verify(self):
if not os.path.isdir(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
if self.leading:
os.makedirs(self.path)
else:
os.mkdir(self.path)
all methods
optional: no
configure()
could be done with
recursive
composition
refactor with
sub-components if too
complex
Wednesday, 3.July 13
class Directory(Component):
namevar = 'path'
leading = False
def verify(self):
if not os.path.isdir(self.path):
raise batou.UpdateNeeded()
def update(self):
ensure_path_nonexistent(self.path)
if self.leading:
os.makedirs(self.path)
else:
os.mkdir(self.path)
all methods
optional: no
configure()
could be done with
recursive
composition
pattern: just wipe
out what's wrong
refactor with
sub-components if too
complex
Wednesday, 3.July 13
CONVERGENCE
resume where
needed
handle many
system states
transparently
avoid
unnecessary
updates
Wednesday, 3.July 13
COMPONENTS
composition of
simple components
no magic bullet, just a
lot easier to factor
your code
configure - verify - update
Wednesday, 3.July 13
Wednesday, 3.July 13
SINGLE-
COMMAND
Wednesday, 3.July 13
REPEATABLE
RELIABLE
Wednesday, 3.July 13
SIMPLE
Wednesday, 3.July 13
ENTROPY
Wednesday, 3.July 13
EXPRESSIVENESS
READABILITY
Wednesday, 3.July 13
REUSABLE
Wednesday, 3.July 13
PLATFORM
INDEPENDENCE
Wednesday, 3.July 13
DOMAIN
AGNOSTIC
Wednesday, 3.July 13
NO ADDITIONAL
RUNTIME
DEPENDENCIES
Wednesday, 3.July 13
CONTINUITY
Wednesday, 3.July 13
MINIMAL
DOWNTIMES
Wednesday, 3.July 13
Wednesday, 3.July 13
PRACTICAL USAGE
Wednesday, 3.July 13
REQUIREMENTS
Python 2.7
SSH
virtualenv
Mercurial
Wednesday, 3.July 13
ENVIRONMENTS
[environment]
service_user = myservice
host_domain = flyingcircus.io
branch = production
[hosts]
multikarl00 = nginx, haproxy
multikarl01 = postgres, redis, memcached, crontab
multikarl12 = supervisor, logrotate, doctotext, myapp
multikarl13 = supervisor, logrotate, doctotext, myapp
Wednesday, 3.July 13
LOCAL
$ bin/batou-local dev localhost
Updating Hello > File(hello) > Presence(hello)
Updating Hello > File(hello) > Content(hello)
$ bin/batou-local dev localhost
$
Wednesday, 3.July 13
REMOTE
$ bin/batou-remote prod
test02.gocept.net: connecting
test01.gocept.net: connecting
test01.gocept.net: bootstrapping
test02.gocept.net: bootstrapping
OK
OK
Deploying test01.gocept.net/hello
Updating Hello > File(hello) > Presence(hello)
Updating Hello > File(hello) > Content(hello)
OK
Deploying test02.gocept.net/hello
Updating Hello > File(hello) > Presence(hello)
Updating Hello > File(hello) > Content(hello)
OK
Wednesday, 3.July 13
OVERRIDES
class Hello(Component):
hostname = "foo"
[environment]
...
[component:hello]
hostname = bar
Wednesday, 3.July 13
SECRETS
class Hello(Component):
db_password = none
secrets/production.cfg
[hello]
db_password = reallysecretstuff
Wednesday, 3.July 13
SECRETS
class Hello(Component):
db_password = none
secrets/production.cfg
[hello]
db_password = reallysecretstuff
SciFi
but
close
Wednesday, 3.July 13
PROVIDE/REQUIRE
class MyApp(Component):
def configure(self):
self.provide('appserver',
self.host.fqdn)
class HAProxy(Component):
def configure(self):
self.backends = 
self.require('appserver')
Wednesday, 3.July 13
PLATFORMS
class HAProxy(Component):
...
@platform('flyingcircus.io', HAProxy)
class SystemWideHAProxy(Component):
def configure(self):
self += File('/etc/haproxy',
ensure='symlink',
link_to=self.parent.haproxy_cfg.path)
Wednesday, 3.July 13
VFS MAPPING
./
...
./work
./work/_/etc/haproxy.cfg
class HAProxy(Component):
def configure(self):
self += File('/etc/haproxy')
[environment]
...
[vfs]
sandbox = Developer
Wednesday, 3.July 13
FEATURES
class MyApp(Component):
features = ['instance', 'jobrunner']
def configure(self):
if 'instance' in self.features:
...
[hosts]
hosta = myapp:instance
hostb = myapp:jobrunner
hostc = myapp:instance, myapp:jobrunner
hostd = myapp
Wednesday, 3.July 13
Wednesday, 3.July 13
CONVERGENCE
COMPOSITION
DETAILS
Wednesday, 3.July 13
QUESTIONS?
Wednesday, 3.July 13
batou.readthedocs.org
pypi.python.org/pypi/batou
bitbucket.org/gocept/batou
Wednesday, 3.July 13

More Related Content

Similar to batou - multi(component|host|environment|.*) deployment

Clojure basics
Clojure basicsClojure basics
Clojure basics
Kyle Oba
 
Lost in o auth? learn velruse and get your life back
Lost in o auth? learn velruse and get your life backLost in o auth? learn velruse and get your life back
Lost in o auth? learn velruse and get your life back
Andrew Mleczko
 
F*cking with fizz buzz
F*cking with fizz buzzF*cking with fizz buzz
F*cking with fizz buzz
Scott Windsor
 
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil BartlettDeploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
mfrancis
 
Seattle.rb 6.4
Seattle.rb 6.4Seattle.rb 6.4
Seattle.rb 6.4
deanhudson
 

Similar to batou - multi(component|host|environment|.*) deployment (20)

Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013   Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013
 
Intro tobackbone
Intro tobackboneIntro tobackbone
Intro tobackbone
 
Workers of the web - BrazilJS 2013
Workers of the web - BrazilJS 2013Workers of the web - BrazilJS 2013
Workers of the web - BrazilJS 2013
 
Taming Pythons with ZooKeeper
Taming Pythons with ZooKeeperTaming Pythons with ZooKeeper
Taming Pythons with ZooKeeper
 
RequireJS
RequireJSRequireJS
RequireJS
 
Rails Intro & Tutorial
Rails Intro & TutorialRails Intro & Tutorial
Rails Intro & Tutorial
 
Clojure basics
Clojure basicsClojure basics
Clojure basics
 
Web directions code 13 notes
Web directions code 13 notesWeb directions code 13 notes
Web directions code 13 notes
 
Keeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro frameworkKeeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro framework
 
Storyplayer
StoryplayerStoryplayer
Storyplayer
 
Lost in o auth? learn velruse and get your life back
Lost in o auth? learn velruse and get your life backLost in o auth? learn velruse and get your life back
Lost in o auth? learn velruse and get your life back
 
How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...
 
How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...
 
Wordpress Plugin Development Practices
Wordpress Plugin Development PracticesWordpress Plugin Development Practices
Wordpress Plugin Development Practices
 
F*cking with fizz buzz
F*cking with fizz buzzF*cking with fizz buzz
F*cking with fizz buzz
 
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil BartlettDeploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
 
Pragmatic JavaScript
Pragmatic JavaScriptPragmatic JavaScript
Pragmatic JavaScript
 
Seattle.rb 6.4
Seattle.rb 6.4Seattle.rb 6.4
Seattle.rb 6.4
 
Engines
EnginesEngines
Engines
 
Continuous Delivery for the Web Platform
Continuous Delivery for the Web PlatformContinuous Delivery for the Web Platform
Continuous Delivery for the Web Platform
 

Recently uploaded

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 

batou - multi(component|host|environment|.*) deployment