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

Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013   Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013 Pablo Godel
 
Workers of the web - BrazilJS 2013
Workers of the web - BrazilJS 2013Workers of the web - BrazilJS 2013
Workers of the web - BrazilJS 2013Thibault Imbert
 
Taming Pythons with ZooKeeper
Taming Pythons with ZooKeeperTaming Pythons with ZooKeeper
Taming Pythons with ZooKeeperJyrki Pulliainen
 
Clojure basics
Clojure basicsClojure basics
Clojure basicsKyle Oba
 
Web directions code 13 notes
Web directions code 13 notesWeb directions code 13 notes
Web directions code 13 notesjaredau
 
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 frameworkJeremy Kendall
 
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 backAndrew Mleczko
 
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...Oursky
 
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...Jane Chung
 
Wordpress Plugin Development Practices
Wordpress Plugin Development PracticesWordpress Plugin Development Practices
Wordpress Plugin Development Practicesserversideup
 
F*cking with fizz buzz
F*cking with fizz buzzF*cking with fizz buzz
F*cking with fizz buzzScott 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 Bartlettmfrancis
 
Pragmatic JavaScript
Pragmatic JavaScriptPragmatic JavaScript
Pragmatic JavaScriptJohn Hann
 
Seattle.rb 6.4
Seattle.rb 6.4Seattle.rb 6.4
Seattle.rb 6.4deanhudson
 
Continuous Delivery for the Web Platform
Continuous Delivery for the Web PlatformContinuous Delivery for the Web Platform
Continuous Delivery for the Web PlatformJarrod Overson
 

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

Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Hyundai Motor Group
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 

Recently uploaded (20)

Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 

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