Planet Inuits
Drupal Development: some tools and utilities
I finally took the time to make my 'drupaldev'-repository available.
First a short introduction: It is my strong opinion that Drupal modules which are only used during development, such as devel, diff, etc, should never be deployed to production. They shouldn't even be in the repository. Instead, I keep a personal collection of development-modules in a separate repo. Thanks to the fact that Drupal recursively searches for modules inside the modules folder, I can simply create a symlink to my collection of development modules. This allows me to use my preferred modules, even though they are not in the repository for the project.
For Drupal7, I usually just create a symlink, named devmodules7, in sites/all/modules. Like this:
1 2 # from the drupal root of the project ln -s ~/drupaldev/devmodules7 sites/all/modules/
The repository itself contains a collection of modules, for both Drupal 6 and Drupal 7, and some utility-scripts. After experimenting with copies of the modules and git submodules, I finally settled on drush make to manage the modules. Instead of copying all the modules in my repo, I only keep a make-file for each Drupal version (currently 6 & 7). This makes it really easy to update all the modules, as I can simply run the makefile again. To make this even easier I have added a build script which will run all the drush make-files with the correct arguments:
1 ./build
Devops in Munich
Devopsdays Mountainview sold out in a short 3 hours .. but there's other events that will breath devops this summer.
DrupalCon in Munich will be one of them ..
Some of you might have noticed that I`m cochairing the devops track for DrupalCon Munich,
The CFP is open till the 11th of this month and we are still actively looking for speakers.
We're trying to bridge the gap between drupal developers and the people that put their code to production, at scale.
But also enhancing the knowledge of infrastructure components Drupal developers depend on.
We're looking for talks both on culture (both success stories and failure) , automation,
specifically looking for people talking about drupal deployments , eg using tools like Capistrano, Chef, Puppet,
We want to hear where Continuous Integration fits in your deployment , do you do Continuous Delivery of a drupal environment.
And how do you test ... yes we like to hear a lot about testing , performance tests, security tests, application tests and so on.
... Or have you solved the content vs code vs config deployment problem yet ?
How are you measuring and monitoring these deployments and adding metrics to them so you can get good visibility on both
system and user actions of your platform. Have you build fancy dashboards showing your whole organisation the current state of your deployment ?
We're also looking for people talking about introducing different data backends, nosql, scaling different search backends , building your own cdn using smart filesystem setups.
Or making smart use of existing backends, such as tuning and scaling MySQL, memcached and others.
So lets make it clear to the community that drupal people do care about their code after they committed it in source control !
Please submit your talks here
Vagrant: Using the shell provider for running puppet.
Why would you use the shell provider instead of the native puppet support?
Sometimes you want to tweak your base-box before running puppet, in that case, using a shell script might be a good idea. I started using the shell provider for deploying a puppetmaster. This way, I can initially bootstrap the puppetmaster using puppet apply and then have further configuration done by letting further configuration be done by just running puppet agent like I would in an actual environment.
The second advantage is that I sync my complete puppet tree to /etc/puppet vagrant box, making the differences with an actual deploy even smaller. If you need custom configuration files, you can use the proper file paths while developing and/or put them in your puppet folder.
This is how my folder structure looks:
. ├── graphs ├── puppet │ ├── hieradata │ ├── manifests │ ├── modules │ └── hiera.yaml ├── scripts │ ├── deploy_puppetmaster.sh │ └── run_puppet.sh ├── README └── VagrantfileAs you can see, stuff is nicely separated. Note that this also allows me to put a hiera.yaml file in place for use with hiera. When using the vagrant puppet provisioning, the hiera.yaml file must be present in the base-box. It also allows me to use git submodules for each part (e.g. the puppet directory which is a collection of more submodules).
Vagrantfile Vagrant::Config.run do |config| config.vm.define :client do |client_config| client_config.vm.box = "base" client_config.vm.host_name = "client" client_config.vm.provision :shell do |shell| shell.path = "scripts/run_puppet.sh" end end end Run PuppetFor running a puppet agent, I use the following script:
#!/bin/bash # set -x ## We need rsync on the machine [ -f /usr/bin/rsync ] || yum install -y rsync # As a (faster) alternative, download the rpm locally and use: # rpm -i /vagrant/rsync-3.0.6-5.el6_0.1.x86_64.rpm ## We need hiera - should be replaced by a rpm someday. [ -f /usr/bin/hiera ] || gem install -r --no-rdoc --no-ri hiera hiera-puppet ## We also need the puppet folder [ -d /etc/puppet ] || mkdir /etc/puppet ## Sync the puppet tree from the vagrant folder to the machine. rsync -alrcWt --del --progress \ --exclude=.git --exclude=.svn \ /vagrant/puppet/* /etc/puppet/ puppet apply --debug --verbose \ --graph --graphdir /vagrant/graphs \ --modulepath /etc/puppet/modules/ /etc/puppet/manifests/site.pp Deploy a PuppetmasterFor deploying / testing a puppet server, I use a slightly different script.
This will first bootstrap the puppet master using the same puppet apply method we use for testing a ‘client’ – but this will only perform minimal configuration. Once we have a puppetmaster running, we run a puppet agent on the machine that will configure the server against itself.
#!/bin/bash # set -x [ -f /usr/bin/rsync ] || yum install -y rsync [ -f /usr/bin/hiera ] || gem install -r --no-rdoc --no-ri hiera hiera-puppet [ -d /etc/puppet ] || mkdir /etc/puppet ## Sync the puppet tree from the vagrant folder to the puppet folder on the machine. rsync -alrcWt --del --progress \ --exclude=.git --exclude=.svn \ /vagrant/puppet/* /etc/puppet/ ## Execute the bootstrap puppet apply --debug --verbose --trace \ --graph --graphdir /vagrant/graphs \ --modulepath /etc/puppet/modules \ -e "import '/etc/puppet/manifests/classes/required-repos.pp' \ import '/etc/puppet/manifests/classes/puppetmaster.pp' \ include puppetmaster::bootstrap" ## Continue configuration using the set up puppetmaster puppet agent --test --debug --verboseI will not go into detail on what the puppetmaster manifest contain (for now) since I am still working on a demo setup. You can take a quick peek to the work that is done on this subject here: https://projects.vstone.eu/projects/puppet-showcase-puppetmaster.
Vagrant and Virtualbox: a debugging story
Recently, I ran into VirtualBox bug #10077:APIC Bug. I wanted to help out so I had to enable console logging to my machine to give useful output. For that same reason, I started setting console=ttyS0 console=tty0 ignore_loglevel to kernel options in grub.cfg on my vagrant-baseboxes.
The apic bug did not occur on every startup so I had to do a lot of them before I got it right. This tempted me to get the console redirect feature of VirtualBox working from within a Vagrantfile. Well, in the end, it’s not that hard…
config.vm.define :base6 do |base_config| base_config.vm.customize [ "modifyvm", :id, "--name", "CentOS 6 x86_64 Base", "--uart1", "0x3F8", "4", "--uartmode1", "file", "/tmp/base6-console.log" ] endNote that this file gets overwritten every time you vagrant up your box. So if you want time stamped logs, you’ll have to introduce some magic (do let me know if you do ;))
FlossUK and Puppetcamp Edinburgh
I've just finished presenting my talk on how I currently work on Puppet modules at Puppetcamp here in Edinburgh where I've been for the week talking on both FlossUK 2012 and Puppetcamp.
7 tools for your devops stackView more presentations from Kris Buytaert
Earlier this week I opened FlossUK 2012 with my talk on 7 tools for your devops stack
How I hack on puppet modulesView more presentations from Kris Buytaert
Devops and Drupal, the Survey, the Results
I've just finished presenting the results of our Drupal and Devops survey at the Belgian Drupal User Group meetup at our office
and I've uploaded the slides to slideshare for the rest of the world to cry read.
Drupal and Devops , the Survey Results View more presentations from Kris Buytaert.Honestly I was hoping for the audience to prove me wrong and I was expecting all of them to claim they were doing automated and repeatable deployments.
But there's hope...
Logstash and ElasticSearch
"An expert is a man who has made all the mistakes which can be made, in a narrow field."
Niels Bohr
When I setup Logstash for the very first time I got bitten by an empty search, aparently no logs were indexed. Reading the log files indeed told me about
- WARN: org.elasticsearch.discovery.zen.ping.unicast: [Blaire, Allison] failed to send ping to [[#zen_unicast_1#][inet[/127.0.0.1:9300]]]
- INFO | jvm 1 | 2012/02/06 22:45:55 | org.elasticsearch.transport.RemoteTransportException: [Page, Karen][inet[/127 .0.0.1:9300]][discovery/zen/unicast]
- INFO | jvm 1 | 2012/02/06 22:45:55 | Caused by: java.io.EOFException
The above is the typical error when the ElasticSearch version you are using externally is not in sync with the one Logstash is using, yes those versions need to match.
Fast forward a couple of weeks.. and I`m upgrading Logstash and therefore also ElasticSearch .. I have a Vagrant setup to play with so all of the components are running on 1 node.
I kept running into a similar problem, this time however I saw log entries being indexed, I could get data from my ElasticSearch setup using
wget -q -S -O - http://localhost:9200/_status?pretty=true
But the web interface kept showing no results ;(
While nagging about it on irc .. Jordan gave me the insight :
2012-01-31.194347+0100CET.txt:(07:55:36 PM) whack: slight caveat that elasticsearch clients also join the cluster, so if you point everyone at 127.0.0.1:9300, that :9300 could be one of your clients, not the server
Indeed when you by accident start any of the logstash instances (server/shipper/web) before you start your ElasticSearch instance you can be in trouble.
Ordering really matters , you really need to start ElasticSearch before you start the clients.
Obviously is you don't use the unicast setup you don't run into this problem ..
So what other mistakes should I make ?
The ultimate 2012 open source and devops conference
Kent Skaar pinged me last week , asking for feedback on Lisa'11 and input for Lisa 2012.
Thought I should share my advise to him with the rest of the world
So If I were to host an event similar to Lisa I'd had either
Jordan Sissel or Mitchell Hashimoto give the keynote because over the past 24 months those people have written more relevant tools for me than anyone else :)
I'd have someone talk about Kanban for Operations, There's 2 names that pop up Dominica DeGrandis and Mattias Skarin
I'd have the Ubuntu folks talk about JuJu and I'd have RI Pienaar talk about MCollective .. while you have RI have him talk about Hiera too. Have Dean Wilson carry RI's bags and put him unknowingly on a panel. (Masquerade it as a Pub with hidden cameras)
Obviously as #monitoringsucks you want to hear about new monitoring tools initiatives and how people are dealing with them , so you want people talking about Graphite, Collectd, Statsd, Sensu , Icinga-MQ And how people are reviving Ganglia and using that in large scale environments.
You want someone to demistify Queues, I mean .. who still knows about the differences between Active, Rabbit , Zero, Hornet and many other Q's ?
You want people talking about how they deal with logs, so talks about Logstash and Graylog2.
You want to cover Test Driven Infrastructure How do you test your infrastructure , someone to demystify Cucumber and Webrat , and talk about testing Charms, Modules, and Cookbooks.
Oh and Filesystems , distributed ones the Ceph, FraunhoverFS, Moose, KosmosFS, Glusters, Swifts of this world ... you want people to talk about their experiences , good and bad with any of the above, someone who can actually compare those rather than heresay stuff. :) With recent updates on what's going on in these projects.
Now someone please organise this for me :) In a warm and sunny place ... preferably with 27 holes next door , and daycare for my kids :)
PS. Yes the absence of any openstack related topic is on purpose .. that's for 2013 :)
We didn't fix it
MonitoringSucks and we didn't fix it.
Earlier this week Inuits hosted a 2 day hackfest titled #MonitoringSucks. A good number of people with a variety of backgrounds showed up on monday morning. I don't know why but people had high expectations for this event , did they really expect us to fix the #monitoringsucks problem in a mere 2 days ?
Next to myselve we had Patrick Debois , Grégory Karékinian, Stefan Jourdan, Colin Humphreys, Andrew Crump, Ohad Levy , Frank Marien, Toshaan Bharvani, Devdas Bhagat, Maciej Pasternacki Axel Beckert Jelle Smet, Noa Resare @blippie , John John Tedro @udoprog, Christian Trabold @ctrabold and obviously some people I missed
A good mixture of Fosdem visitors that stayed a litte longer in our cold country and locals with ideas. We had people from TomTom, RedHat , Spotify, Booking.com, Inuits, Atlassian, coming from Belgium, The Netherlands France, Israel, the UK, Sweden, Germany, Poland and Switzerland if I`m not mistaken.
The format was pretty open, much of the first day was spend around the drawingboard.
(Ohad Levy, Jelle Smet, PatrickDebois and Frank Marien) discussing a variety of topics
This monitoring topic is complex, there are different areas that need to be covered. The drawing below documents how we splitted the problem into different areas , and listed the different tools people use for these areas.
- Collection: Collectd, Nagios, Ganglia
- Transport: XMPP, Smiple, Smtp, 0mq , APMQ, rsyslog, irc, stomp
- Storage : rrd, graphite, opentsdb, hbase,
- Filtering: logstash, esper,
- Visualisation : Graphite,
- Notifcation: PagerDuty
- Reporting: Jasper
Obviously above list is far from complete.
The afternoon discussion continued where we left of before lunch, just after the powercut. Only now we started refocussing on filtering and aggregating values using Logstash
@patrickdebois had been talking about the idea to use Logstash as a way to collect data , transform it and throw it either to another tool, or onto a Queue before.
Looking at Logstash it makes kind of sense. Logstash already has a zillion of input types, filters and outputs. Including popular queues such as amqp and zeromq. Yes, the default behaviour for a lot of people is to get data from different inputs, filter it and then send it to ElasticSearch, but much more is possible with the available outputs.
It was only on tuesday that people really started writing code
So what did really come out of the #monitoringsucks hackfest. ?
A couple of people were working on packaging existing tools for their favourite distro. Others were working on integrating a number of other already existing tools (e.g Patrick working on more inputs for Logstash., me working on replacing logster with Logstash, setting up Kibana etc. New tools were learned, items were added to todolists (Kibana, (doesn't work on older Firefox instances) Tattle, statsd) and items were scratched from todolists (Graylog2 (Kibana replaces that as a good Frontend for Logstash) )
A lot of experiences with different tools were exchanged
Frank Marien showed us a demo of his freshly release ExtremeMon framework. A really promising project.
The sad part about a workshop like this one is that you enter with a bunch of ideas , and leave with even more ideas, hence more work. We haven't solved the problem yet, but a lot of more people are now thiking about the problem and how to solve it a more modulare (unix style) approach. With different litte tools, all being good at something and all being interconnectable.
#monitoringsucks hackathon 6&7 february Practical details:
As announced earlier next monday and tuesday we're opening up the Inuits offices for everybody working on monitoring problems.
There's already a good number of people that have confirmed their presence and some people have asked
As for practical details .. the plan is simple.
I`m going to be at the place somewhere between 8:30 and 9:00 on monday. ( Hey .. it's the day after Fosdem you know :))
The only thing I've planned is to do a get to know eachother round around 10:30 after that I`m expecting the hackathon to be self organising,
There will be water, coffee , etc , IP connectivity, and electricity.
The location is still Duboisstraat 50, Antwerp
Free parking is on the Hardenvoort or Kempenstraat ( 3minutes walk) , paid parking right in front of the door.
Why not to use Puppet::Parser::Functions.autoloader.loadall
Recently (about 5 minutes ago), I was writing a custom puppet-function to offload some puppet magic. In short: I’m writing a wrapper around create_resources so I can keep syntax for the end-users of my module crispy clean. This means I need the create_resources function to be available in my custom function. This can be done by using Puppet::Parser::Functions.autoloader.loadall as suggested on the puppetlabs custom modules guide. Unfortunately, when using #loadall, all functions will be loaded.
Why unfortunately? In my case: A function defined in puppet-foreman depends on the rest-client gem and I do not have this installed. Some people might say: Just install the gem and be done with it! This is hardly a proper solution. The way to go would to be only include the function I really need, being create_resources.
And here is how:
Puppet::Parser::Functions.autoloader.load(:create_resources) unless Puppet::Parser::Functions.autoloader.loaded?(:create_resources)This will basically load the create_resources function after checking that it has not been loaded before. This (the function already being loaded) could be the case if you properly depend on puppetlabs-create_resources in your manifests. Side note: I added a small dummy class so my modules can depend on this function being available.
This has resolved my issues with #loadall, but if I ever needed to include another function that DOES use #loadall, I’ll be screwed all over again. So (pretty) pls, don’t use #loadall.
Puppet Module Patterns
I’ve used puppet quite intensively since a couple of months (about 4 I would guess). Before that, I’ve played with it, change something here and there. But quite not as much as now. I’ve used several puppet modules from wherever google leads me, roamed github, inherited a few from colleagues and created several from scratch. While doing so, I saw a lot of stuff I disliked and learned a lot on how we I can (ab)use puppet to do what I want it to do. Over those last months, I have grown my set of ideas on how a puppet module should look. So, before every statement I make, you should probably add ‘IMHO’.
WHO THE F.Why the hell would this guy (me) have anything to say about puppet modules. Let’s situate first.
I’m now an Open Source Consultant. I’ve been (in order) a Java programmer, sysadmin, Drupal developer and now back sysadmin (doing devopsy things). Last 3 positions I worked for (and still work for): Inuits – Open Source company in Belgium. Currently, I’m positioned at UnifiedPost (About 100 people but thinking big!). I help out with daily maintenance (and there is plenty) and starting to adopt puppet as much as possible. Puppet was already in use at UP (UnifiedPost), but knowledge was rather thin as I came in. They did however manage some hosts with it (about 300-400). I dove in the puppet code rather fast and stumbled upon several patterns that increased pressure on my mouse heavily. Even modules I grabbed from the net (whatever the source is) made my grip firmer.
PROBLEMSBefore trying to fix the problem, we should find exactly what bothers me with all these modules I lay my eyes on. I’ll try to keep it organized.
- Modules are not classes!
- Too hard to use by non-developers
- Poor interaction with third-party modules
- Not versioned
- Not pretty at all do down right f_ugly
Although a module exists out of several classes, it should not behave like one.
An example to clarify what I mean: The accounts module. (I’m sure this is the case for may organizations that have an accounts module).
I can think of a several valid reasons why you would have one. (Keep reading nevertheless!). What does our accounts module contain: A definition to ease the use and do some customization (set defaults, create some files, …). We also find a list of users, passwords and authorized_ssh keys. This (specific) user information does not belong in a module. It should either be in a class (below the manifests folder) or stored externally. In my point of view: Nodes use classes. They register the kind of machine and define what should be installed. Classes include modules and change settings. Possibly parameterized so we can keep it node specific. All module parameters values reside in the node or the class(es) it includes.
2. Too hard to use by non-developersThis brings us to our next point. Can I just grab your module and start using it? Or do I need to weed out hardcoded strings, change host names or edit templates. Do I need to understand the complete way it works ‘under the hood’. I have written a short post recently, expressing my feelings about this. Bottom line: If I need to edit any file within your module to get it working the way I want it to, there is something wrong with it. Sure, features and/or support might be missing. but if my $::operatingsystem is supported, I should get it working without touching anything of the module code.
3. Poor interaction with third-party modulesI have reused (or attempted to) several modules found on github and always had the same problem, it does not play well with our current puppet-tree. The best example for this is probably the apache (or httpd) module. Almost any puppet modules that has a dependency on apache being installed, comes with its own implementation and/or dependency. Most companies already have a apache module and change the new module to work properly together with theirs. There goes upstream support. I have run into this issue with puppet-foreman recently and this will probably be my first big test case for my coding pattern.
4. Not versionedMost modules you will find only live on one branch, master. Some may have a develop branch, but most of the time, there is no saying in what version you are using. Unless you elevate hash-tags to version numbers. (Using git submodules does this at some extend). But updating a submodule is always a dangerous thing to do, there is no way to tell what will break.
Besides the ‘version’ of a module, we also have to take the puppet version into account. I tend to be a cutting-edge user for all my software, but I can easily understand if you don’t for whatever reason. So keeping puppet-modules backwards compatible is a must (is it?).
5. Not pretty at all do down right f_uglyWhy is properly formatted code important: for anybody else that ever has to ever change or even use it. This could be a colleague or someone (anyone) else that found your module and wants to improve (here is when YOU win time, if somebody else does the job for you) or change it. Even if you did not have time for writing up documentation, most people will have to stroll through your code. Having properly formatted code is always a nice-to-have feature then.
REQUIREMENTSSo now that we know what I dislike about puppet modules, let’s try to define something more positive. What is a good baseline for a puppet-module.
- VCS (This one is pretty obvious, I will not elaborate on this any further.)
- Follows style guidelines
- Use of centralized parameters / settings
- Fully(!) parameterized
- Easy and centralized handling of compatibility ($::operatingsystem-ish stuff)
- Documented
- Releases
- Puppet compatibility
- Integration: is uniquely identifiable
- Easy to extend
Why? Some valid reasons are so you make fewer mistakes and are more aware of what you are doing Do you really need double quotes? Using single quotes for static string values will prevent you from forgetting to quote ‘$’ (commands anyone?). Always using a default case will make you more aware that more than one distro exists in the world. At least fail when your module is not fit for a certain operating system to prevent unexpected behavior. If you read through the style guideline, you will see that many of these items are easily to do if you just remember to do so when you are writing the actual code.
2. Centralized parameters / settingsDoes your module support distro? Just check the params.pp file. Everything is there. It does not get much easier than this to add support for a new distro.
3. Fully ParameterizedThis might seem like I’m making the same point twice, but we should differentiate between our general ‘settings’ that configure the working of our module, and specific definitions that have parameters. You define where all your vhosts are but each vhosts definition you create also takes parameters. Same rule applies for a definition as for a module, we should be able to use it without having to change anything in the code. Often, this means making more stuff than you need – at time of writing your module – dynamical (parameterized). You can hard-code a ‘Listen 80′ or template it using a $ports parameter.
4. Compatibility handlingAs an exampe: my colleague asked me: Does your module work for Debian? I was happy to answer: You just need to add support to the params.pp file. That’s all whats needed (and maybe add some templates).
5. DocumentationWhen thinking as a developer when writing a module, we know we need to offer easy documentation for the end-user. This is no different when writing a puppet module. It’s always a good thing to keep people out of your code as much as possible. Proper documentation is the first step. I try to write as much as possible, main reason being when a colleague asks how to use it, I can point him to the documentation instead of going over the code myself to remember what exactly is going on. On a side note: ATM, I’m having some troubles with bug #11384. Votes – and a patch even more – welcome ;)
Beside top-level documentation, inline (code) documentation should also be written. Not for the obvious stuff, but when you do something more advanced, explain to a fellow coder (or yourself some weeks later) why and what you are doing.
6. ReleasesPuppet modules should also have releases. This would an easier way of drawing attention when we change the API (or definition parameters) or when we fix a bug. This is also a great sign when our module is no longer backward compatible with old code (breaking API). I try to support old code as much as possible. But at some point, we will have to weed the old so it does not clutter the new. Keeping stuff simple/stupid (although I have passed that bridge a looooong time) is still a good principle.
7. Puppet CompatibilityWe need to know with what version of puppet your module is compatible. Some features of the puppet language you use might or might not be available in older releases. You can check the Puppet Language Guide for what is introduced in what version, but there are a lot of other differences that are not so much documented. I’ve been using the create_resources function quite a lot but it’s only in core puppet for versions 2.7 and up. Luckily, there is a backport for 2.6 on the puppetlabs’ github.
8. Integration: is uniquely identifiableTo improve compatibility, we first need must be able to tell what module we are integrating with. I personally started to use a $modulename and $moduleversion param in the main class of my module. Modulefiles like puppetlabs requires them for the puppet forge are cool, but we can not use them in our code. We could write a fact for this so we don’t need to duplicate code. I won’t add this to my to-do list as I already have a way-to-long backlog, but feel free to add it to yours.
With this information, we could do different things based on the module and version we are working with.
9. Easy to extendIn this part, the developer in me is taking the overhand and it will depend on personal preference a lot more than any of the previous points. A quick example: I wanted to use a conf.d/* configuration style. Even more, for certain configuration files, order is important so we need to prefix files with 00_, 01_, … I could have easily done this for each type of configuration file I want to store here. In stead, I wrote a confd wrapper definition/class that does this for me. It’s a 2 step process: You initialize/setup a conf.d folder and then define yourresources within them. I’m realizing now that this should have been a separate module. I have added it to my to-do list.The main advantage is I can easily re-implement conf.d style folders now without worrying about the logic behind it.
SOLUTIONSQuick wins! These go without saying, start using them now.
Check your code for formatting and style.For this, we have puppet-lint. This tool will deal with most common problems and errors/warnings against the style guide. This tool takes one puppet manifest as argument and displays the errors/warnings it finds. You can easily integrate it with jenkins since the log-format argument has been added.
Documentation.I suppose most people will have issues with this. Good documentation is essential and not much hard work if you do it right. I prefer to START with documenting what a class will do and implement afterwards. This is a lot like writing tests first and then use them to see if you are writing proper / working code. The danger is of course that you change the internal working but forget to update your documentation. After each feature I add, I tend to go over the documentation and see that everything is still up to date. Once documentation has been written, you can generate it using puppet doc. To work around certain puppet doc’s ugliness, I wrote a small wrapper script for my Jenkins jobs that does some post processing on them. See previous post for that.
ReleasesI’ll be quick about this one: Use git-flow.
General / Initial module structure.For creating your initial puppet module structure, there is always the puppet-module tool. Install it by installing the gem. I have tried using it, but I’m relying on my own bash magic for creating classes.
This is my basic structure I re-use over and over.
- ./manifests/init.pp
- ./manifests/params.pp
- ./manifests/packages.pp
- ./manifests/setup.pp
One note on these filenames: always try to avoid confusion! I have seen a lot of config.pp classes and params.pp classes where the config.pp actually does configuration of the package on the system while params.pp is for configuring the behavior of the puppet-module. I like setup.pp better than config.pp, since it’s easier to figure out what the class does: It sets up the system! Another good option would be install.pp.
OUTROI realize these solutions are no where near finished but since FOSDEM 2012 is coming up and I’m running low on time, I wanted to publish this post so anybody can starting giving their opinion on the matter before coming to a final out-of-the-box solution most people can relate to. So, actually, this is a big fat TO BE CONTINUED.
Matters we need to discuss:
- Compatibility handling (both to other modules and puppet)
- Making modules easy to integrate and/or extend.
SUID flag of a file magically disappeared
If you set a SUID flag on a file, this flag will disappear when the ownership (user or group) is changed of that file!
Let me show you:
[root@raskas ~]# touch test
[root@raskas ~]# ll test
-rw-r--r-- 1 root root 0 2011-06-22 17:10 test
[root@raskas ~]# chmod u+s test
[root@raskas ~]# ll test
-rwSr--r-- 1 root root 0 2011-06-22 17:10 test
[root@raskas ~]# chown johan:johan test
[root@raskas ~]# ll test
-rw-r--r-- 1 johan johan 0 2011-06-22 17:10 test
[root@raskas ~]# chmod u+s test
[root@raskas ~]# ll test
-rwSr--r-- 1 johan johan 0 2011-06-22 17:10 test
[root@raskas ~]# chown root:root test
[root@raskas ~]# ll test
-rw-r--r-- 1 root root 0 2011-06-22 17:10 test
[root@raskas ~]#
Heartbeat v3. resource-stickiness
We are running a heartbeat cluster with several resource groups. One of these groups is depending on a drbd disk which is configured as a master/slave resource.
Everything was working fine with heartbeat v3.0.1 and pacemaker v1.0.7…
Until we upgraded to heartbeat v3.0.3 and pacemaker v1.1.5.
When we tried to swap the resource group depending on the drbd disk, the resource group was stopped but the drbd master / slave resource refused to demote the current master.
Resulting in the unavailability of the resource group.
Mentioning this problem on #linux-ha they pointed me to resource-stickiness in the configuration.
In our configuration the resource-stickiness is set to INFINITY, we have configured it like that because we only want resources to swap during a failure or when manually requested, in all other cases the resource should remain on the node where it currently is. This is not the case when the resource-stickiness is not configured.
Apparently setting it to INFINITY was a bit radical, setting the resource-stickiness to 1000 is sufficient. The resources only swaps during a failure or manually triggered and the drbd master / slave resources follows the resource group using it.
Vagrant up!
Found some time to recreate a test environment for various things once and again. The ‘previous version’ used libvirt to control KVM instances with bridged networking. All of this quite well working setup was running on my home ’server’. On my day-to-day work laptop I have been using Virtualbox to quickly test some stuff from time to time. And that’s why Vagrant got my attention.
After a very quick re-install of my old and beloved linux distro Arch Linux (got it booted from the LVM root finally, thank you dracut) it was time to get going.
Installation of Vagrant is a breeze (no distro packages yet, just a gem)
Following the quick start on their site got me going in no time.
I stopped right after getting port forwards in. The next step handled packaging your configured VMs, which Vagrant builds using some base image downloaded somewhere. Getting a base image might already be a bit evil (who knows what ‘base’ means to someone else anyway) , and packaging your configured instance afterwards is just more evil
So I enabled my favourite config management tool (Vagrant had default Chef and Puppet support), added the manifests, and that’s all that’s needed. Next time you ‘vagrant up’ it’ll re-apply it all.
Right now, I’m having a look at Veewee, kind of an ‘addon’ tool to create your own ‘boxes’!

