fixing growing pains with puppet data patterns
DESCRIPTION
Using the Puppet Common data pattern to scale puppet across multiple environments using the same code base.TRANSCRIPT
• We started out using puppet and everything was good:
– That Puppet, Redmine & Subversion stuff we put in is Da Bomb!
• Create a Redmine ticket for each request
• Hack around in puppet
• Commit using Redmine tag
• Auditability and trace ability - who did what and why
– It was all good until….
Life is was good…
• We created multiple environments
– Development
– QA
– Integration
• All on the same network so no problem!
• Easily sorted with a little RegEx action
• Problem sorted, err well sort of until….
Multiple Environments!
• Then we created multiple environments in different locations with no direct network access between each, so things got a little tricky:
ssh env-1.jumphost.office
svn export puppet-module
scp -r puppet-module colo1-puppetmaster.colo1:.
ssh colo1-puppet.master
rsync -av puppet-module /etc/puppet/modules/
vi /etc/puppet/modules/puppet-module/manifest/init.pp #customise to env
vi /etc/puppet/manifest/nodes.pp #enable new module functionality
pushd /etc/puppet
svn ci -m "Feature #404 - New version of puppet-module installed“
• We did this up to a point until…
Disconnected Networks!
• Keeping multiple puppet environments in sync was becoming a serious pain:
Environment 1.svn export code
tar code
copy code
untar code
rsync code to newcode location
edit code like crazy till it works
svn add code
svn commit code
Environment 2. Rinse and repeat
Environment X. Rinse and repeat
SYNCHRONIZATION PAIN!
http://puppetlabs.com/blog/design-pattern-for-dealing-with-data/
Puppet Common Data Pattern
class common{
include common::data
}
class common::data {
# ensure that the $env variable has been set
# valid values are: 'vagrant', 'development', 'qa', 'staging', 'integration',
'training', 'production'
if ! ( $env in [ 'vagrant', 'development', 'qa', 'staging', 'integration',
'training', 'production' ] ) {
fail("common::data env must be one of: 'vagrant', 'development',
'qa', 'staging', 'integration', 'training', 'production'")
}
# environment specific data
case $env {
'vagrant': {
$domainname = "uncommonsense.local"
$searchpath = ["uncommonsense.local"]
$nameservers = ["192.168.1.10", "192.168.20", "8.8.8.8", "8.8.4.4"]
$ntpServerList = [ '0.uk.pool.ntp.org', '1.uk.pool.ntp.org' ]
$ldap = {host => ‘ldap.uncommonsense.local', port => ‘3389', baseDN =>
'dc=uncommonsense,dc=bogus', adminDN => 'cn=ldapmeister,dc=uncommonsense,dc=bogus',
password => ‘myspoonistoobig'}
} # vagrant:
http://puppetlabs.com/blog/design-pattern-for-dealing-with-data/
Leveraging the Data Pattern
node ‘ldapserver.dev.uncommonsense.local’ {
$env = ‘development’
include common
include localenvironment
include openldap
include ldap::server
}
$basedn = $common::data::ldap[baseDN]
$admindn = $common::data::ldap[adminDN]
$password = $common::data::ldap[password]
class openldap::common {
case $common::data::ldap[baseDN] {
"": { fail('$common::data::ldap[baseDN] not set for environment') }
}
case $common::data::ldap[adminDN] {
"": { fail('$common::data::ldap[adminDN] not set for environment') }
}
case $common::data::ldap[password] {
"": { fail('$common::data::ldap[password] not set for environment') }
}
}
Nodes.ppNodes.ppNodes.ppNodes.pp::::
OpenldapOpenldapOpenldapOpenldap----common.ppcommon.ppcommon.ppcommon.pp:
• We picked a master and stuck with it (i.e. the one attached to Redmine)
• All changes made and tracked within one environment
• Other Environments refreshed as needed as a complete replacement copy no more ad-hoc edits
• Bliss!
• But what about git? Doesn’t git make this is much easier because it’s a DVCS? Unfortunately….
Common Code Base
Questions
Links• http://puppetlabs.com
• http://puppetlabs.com/blog/design-pattern-for-dealing-with-data/
• http://devopswire.com/patterns/environment-abstraction
• http://subversion.apache.org
• http://www.redmine.org
• http://vagrantup.com
• http://git-scm.com