{"id":471,"date":"2009-09-28T21:31:57","date_gmt":"2009-09-28T20:31:57","guid":{"rendered":"http:\/\/wp.devco.net\/?p=471"},"modified":"2012-12-13T01:41:48","modified_gmt":"2012-12-13T00:41:48","slug":"simple_puppet_module_structure","status":"publish","type":"post","link":"https:\/\/www.devco.net\/archives\/2009\/09\/28\/simple_puppet_module_structure.php","title":{"rendered":"Simple Puppet Module Structure"},"content":{"rendered":"
Note:<\/B> While this post is still relevant, you should also check the newer Simple Puppet Module Structure Redux<\/a> post<\/p>\n Puppet<\/a> supports something called Modules<\/a>, it’s a convenient collection of templates, files, classes, types and facts all related to one thing.\u00a0 I find it makes it easy to think about a problem in an isolated manner and it should be the default structure everyone use.<\/p>\n Usually though the problem comes with how to lay out modules and how to really use the Puppet classes system, below a simple module layout that can grow with you as your needs extend.\u00a0 I should emphasis the simple here – this example does not cater well for environments with mix of Operating Systems, or weird multi site setups with overrides per environment, but once you understand the design behind this you should be able to grow it to cater for your needs.\u00a0 If you have more complex needs, see this post as a primer on using the class relationships effectively.<\/p>\n For the most part I find I make modules for each building block – apache, syslog, php, mysql – usually the kind of thing that has:<\/p>\n You can see there’s an implied dependency tree here, the config steps require the package to be installed and the service step require the config to be done.\u00a0 Similarly if any config changes the services might need to restart.<\/p>\n We’d want to cater for the case where you could have 10 config files, or 10 packages, or 100s of files needed to install the service in question.\u00a0 You really wouldn’t want to create a big array of require =><\/em> resources to control the relationships or to do the notifications, this would be a maintenance nightmare.<\/p>\n We’re going to create a class for each of the major parts of the module – package, config and service.\u00a0 And we’ll use the class systems and relationships, notifies etc to ensure the ordering, requires and notifies are kept simple – especially so that future changes can be done in one place only without editing everywhere else that has requires.<\/p>\n <\/code><\/p>\n If we now just do include ntp<\/em> everything will happen cleanly and in order.<\/p>\n There’s a few things you should notice here.\u00a0 We’re using the following syntax in a few places:<\/p>\n All of the usual relationship meta parameters can operate on classes, so what this means is if you require Class[“ntp::config”] then both ntp.conf<\/em> and step-tickers<\/em> will be created before the service starts without having to list the files in your relationships<\/em>.\u00a0 Similarly if you notify a class then all resources in that class gets notifies.<\/p>\n The preceding paragraph is very important to grasp, typically we’d try to maintain arrays of files in require trees and later if we add a new config file we have to go hunt everywhere that needs to require it and update those places, by using this organization approach we never have to update anything. \u00a0 If I add 10 services and 100 files into the config and service classes everything else that requires ntp::service<\/em> will still work as expected without needing updates.<\/p>\n This is a very important decoupling of class contents with class function.\u00a0 Your other classes should never be concerned with class contents only class function.<\/p>\n As a convention this layout is a good sample, if all your daemons gets installed in the daemon::install <\/em>class you’ll have no problem knowing where to find the code to adjust the install behavior – perhaps to upgrade to the next version – you should try to come up with a set of module naming conventions that works for you and stick to it throughout your manifests – I have a rake task to setup my usual module structure, they’re all the same and the learning curve for new people is small.<\/p>\n By building up small classes that focus on their task or subtask you can build up ever more powerful modules.\u00a0 We have a simple example here, but you can see how you could create ntp::master<\/em> and ntp::client <\/em>wrapper classes that would simply reuse the normal ntp::install<\/em> and ntp::service<\/em> classes.<\/p>\n As I mentioned this is a simple example for simple needs, the real take away here is to use class relationships and decouple the contents of those classes with their intent this should give you a more maintainable code set.<\/p>\n Ultimately conventions such as these will be needed to get us all one step closer to being able to share modules amongst each other as the specifics of making Apache on different distributions work will not matter – we’d just know that we want Class[“apache::service”]<\/em> for example.<\/p>\n","protected":false},"excerpt":{"rendered":" Note: While this post is still relevant, you should also check the newer Simple Puppet Module Structure Redux post Puppet supports something called Modules, it’s a convenient collection of templates, files, classes, types and facts all related to one thing.\u00a0 I find it makes it easy to think about a problem in an isolated manner […]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","footnotes":""},"categories":[7],"tags":[121,21],"_links":{"self":[{"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/posts\/471"}],"collection":[{"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/comments?post=471"}],"version-history":[{"count":14,"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/posts\/471\/revisions"}],"predecessor-version":[{"id":2866,"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/posts\/471\/revisions\/2866"}],"wp:attachment":[{"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/media?parent=471"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/categories?post=471"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devco.net\/wp-json\/wp\/v2\/tags?post=471"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}\n
<\/p>\n
\r\nclass ntp::install {\r\n package{\"ntpd\":\r\n ensure => latest\r\n }\r\n}\r\n\r\nclass ntp::config {\r\n File{\r\n require => Class[\"ntp::install\"],\r\n notify => Class[\"ntp::service\"],\r\n owner => \"root\",\r\n group => \"root\",\r\n mode => 644\r\n }\r\n\r\n file{\"\/etc\/ntp.conf\":\r\n source => \"puppet:\/\/\/ntp\/ntp.conf\";\r\n\r\n \"\/etc\/ntp\/step-tickers\":\r\n source => \"puppet:\/\/\/ntp\/step-tickers\";\r\n }\r\n}\r\n\r\nclass ntp::service {\r\n service{\"ntp\":\r\n ensure => running,\r\n enable => true,\r\n require => Class[\"ntp::config\"],\r\n }\r\n}\r\n\r\nclass ntp {\r\n include ntp::install, ntp::config, ntp::service\r\n}<\/pre>\n
\n