Montag, 27. Juni 2011

Puppet, iterating over a hash

Today i fiddled about how to iterate over a hash in a puppet function (define). Okay, it is a bit .. scary but it works ;-)
define mymodule::myfunction($options = {}) {
     $cli_parameter = inline_template(
          "<% options.each_pair { |key, val| %> --<%= key %>=<%= val %><% } %>");
     // ...
}

Samstag, 25. Juni 2011

Managing Servers with (R)?ex

Rex is a tool to automate the management of servers. In this blog post i will just post an example of managing some webservers with mod_jk and tomcat.

Every webserver has the same file system structure and the same os (but this is negligible).


To prepare a new webserver i've written a task to install all the needed packages, copy the configuration files and start all the required services.


This is my Rexfile.
use lib 'lib';
user "root";      # set your username
password "pass";  # set your password
pass_auth;        # enable password authentication

# put your server in this group
group "www" => "www[01..05]";

# now load every module via ,,require''
require Rex::mysite;
I've splittet the different tasks in some smaller modules.

This is the module for all the base tasks. (Saved under "lib/Rex/mysite.pm")

package Rex::mysite;

use Rex::Commands;
use Rex::Commands::Fs;
use Rex::Commands::Run;
use Rex::Commands::Pkg;
use Rex::Commands::Upload;
use Rex::Hardware;

use Data::Dumper;

use Rex::mysite::plain;

desc "Prepare system";
task "prepare", group => 'www', sub {

   my %host_info = Rex::Hardware->get(qw/ Host /);

   if($host_info{'Host'}->{'operatingsystemrelease'} =~ m/^5/) {
      install file => "/etc/apt/sources.list", {
         source => "files/sources.list.lenny",
      };
   }
   else {
      install file => "/etc/apt/sources.list", {
         source => "files/sources.list.squeeze",
      };
   }

   if(! is_dir("/root/.ssh")) {
      mkdir "/root/.ssh";
   }

   upload "files/authorized_keys", "/root/.ssh/authorized_keys";

   run "apt-get update";

   install package => "vim";
   install package => "less";

   remove package => "avahi-daemon";
};


1;
And now i have a task to install the tomcat server and configure the apache servers with mod_jk.  (Saved under "lib/Rex/mysite/plain.pm"). With the needs function i define a dependency to the prepare Task in the module Rex::mysite. So this task will be executed always in the same context (same ssh connection) of the tomcat Task in this module.
package Rex::mysite::plain;

use Rex::Commands;
use Rex::Commands::Fs;
use Rex::Commands::Run;
use Rex::Commands::Pkg;
use Rex::Commands::Upload;
use Rex::Commands::Service;

use Data::Dumper;

desc "Prepare Tomcat";
task "tomcat", sub {
   needs Rex::mysite "prepare";

   run "echo sun-java6-jdk shared/accepted-sun-dlj-v1-1 select true | /usr/bin/debconf-set-selections";
   run "echo sun-java6-jre shared/accepted-sun-dlj-v1-1 select true | /usr/bin/debconf-set-selections";

   install package => [
                        "sun-java6-jdk",
                        "libapache2-mod-jk",
                        "sc-tomcat-6.0.28",
                        "sc-tomcat-juli-6.0.28",
                        "sc-tomcat-log4j-1.2.16"
                     ];

   unlink "/etc/apache2/sites-enabled/000-default";
   upload "files/000-default", "/etc/apache2/sites-enabled/000-default";
   upload "files/jk.conf", "/etc/apache2/mods-enabled/jk.conf";

   install file => "/etc/apache2/workers.properties", {
      source    => "files/workers.properties.tpl",
      on_change => service(apache2 => "restart"),
   };

};

1;
The files i uploaded in these tasks are not realy interesting. They are just simple configuration files. Except the file workers.properties.tpl. This i a template file and looks like this.
worker.list=lb,jkstatus

worker.w1.port=8009
worker.w1.host=<%+ $::Network->{"networkconfiguration"}->{"eth0"}->{"ip"} %>
worker.w1.type=ajp13
worker.w1.lbfactor=1
worker.w1.reference=worker.template

worker.lb.type=lb
worker.lb.balance_workers=w1
worker.lb.max_reply_timeouts=10

worker.lb.sticky_session=false
worker.jkstatus.type=status

worker.template.type=ajp13
worker.template.connection_pool_timeout=600
worker.template.connection_pool_minsize=0
This is a template file. During the upload process Rex will parse this template and replace <%+ $::Network->{"networkconfiguration"}->{"eth0"}->{"ip"} %> with the ip of the networkdevice eth0.

With these tasks i can update the configuration of all my servers realy simple. If a new server needs to be installed i can just run the task on this server.

$ rex -H mynewserver mysite:plain:tomcat