[PATCH 1/1] Implement a Puppetmaster inside Passenger

9 views
Skip to first unread message

Christian Hofstaedtler

unread,
Sep 25, 2008, 12:25:22 PM9/25/08
to puppe...@googlegroups.com
This consists of a new Puppet::Network::HTTPServer::Rack,
plus configuration details for Passenger.

Signed-off-by: Christian Hofstaedtler <hofsta...@inqnet.at>
---
ext/passenger/README | 63 ++++++++++++++
ext/passenger/apache2.conf | 29 ++++++
ext/passenger/config.ru | 40 +++++++++
lib/puppet/network/http_server/rack.rb | 148 ++++++++++++++++++++++++++++++++
4 files changed, 280 insertions(+), 0 deletions(-)
create mode 100644 ext/passenger/README
create mode 100644 ext/passenger/apache2.conf
create mode 100644 ext/passenger/config.ru
create mode 100644 lib/puppet/network/http_server/rack.rb

diff --git a/ext/passenger/README b/ext/passenger/README
new file mode 100644
index 0000000..fcdcb91
--- /dev/null
+++ b/ext/passenger/README
@@ -0,0 +1,63 @@
+
+PUPPETMASTER INSIDE APACHE & PASSENGER
+======================================
+
+This is about running a puppetmaster inside Apache.
+
+Please also see the docs at http://reductivelabs.com/trac/puppet/wiki/UsingPassenger
+for further information.
+
+
+WHAT IS IT?
+===========
+
+Passenger [1] (AKA mod_rails or mod_rack) is an Apache 2.x Extension for
+serving Rails or Rack applications.
+
+This extension allows running a puppetmasterd as a Rack application;
+it has only been tested with Passenger.
+
+
+SHORT INSTALLATION INSTRUCTIONS
+===============================
+
+Make sure puppetmasterd ran at least once, so the SSL certificates
+got set up.
+
+Install Rack:
+ gem install -v 0.4.0 rack
+
+Install Apache and Passenger:
+ apt-get install apache2
+ gem install passenger
+ passenger-install-apache2-module
+ (See the Passenger installation instructions [2] for details.)
+
+Enable Apache modules:
+ a2enmod ssl
+ a2enmod headers
+
+Configure Apache:
+ cp apache2.conf /etc/apache2/conf.d/puppetmasterd
+ vim /etc/apache2/conf.d/puppetmasterd (replace the server hostnames)
+
+Install the rack application [3]:
+ mkdir -p /usr/share/puppet/rack/puppetmasterd
+ mkdir /usr/share/puppet/rack/puppetmasterd/public /usr/share/puppet/rack/puppetmasterd/tmp
+ cp config.ru /usr/share/puppet/rack/puppetmasterd
+ chown puppet /usr/share/puppet/rack/puppetmasterd/config.ru
+
+Go:
+/etc/init.d/apache2 restart
+
+
+
+[1] http://www.modrails.com/
+
+[2] http://www.modrails.com/install.html
+
+[3] Passenger will not let applications run as root or the Apache user,
+instead an implicit setuid will be done, to the user whom owns
+config.ru. Therefore, config.ru shall be owned by the puppet user.
+
+
diff --git a/ext/passenger/apache2.conf b/ext/passenger/apache2.conf
new file mode 100644
index 0000000..6a8a974
--- /dev/null
+++ b/ext/passenger/apache2.conf
@@ -0,0 +1,29 @@
+Listen 8140
+<VirtualHost *:8140>
+ SSLEngine on
+ SSLCipherSuite SSLv2:-LOW:-EXPORT:RC4+RSA
+ SSLCertificateFile /var/lib/puppet/ssl/certs/puppet-server.inqnet.at.pem
+ SSLCertificateKeyFile /var/lib/puppet/ssl/private_keys/puppet-server.inqnet.at.pem
+ SSLCertificateChainFile /var/lib/puppet/ssl/ca/ca_crt.pem
+ SSLCACertificateFile /var/lib/puppet/ssl/ca/ca_crt.pem
+ # If Apache complains about invalid signatures on the CRL, you can try disabling
+ # CRL checking by commenting the next line.
+ SSLCARevocationFile /var/lib/puppet/ssl/ca/ca_crl.pem
+ SSLVerifyClient optional
+ SSLVerifyDepth 1
+ SSLOptions +StdEnvVars
+
+ # The following client headers allow the same configuration to work with Pound.
+ RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
+ RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
+ RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e
+
+ RackAutoDetect On
+ DocumentRoot /usr/share/puppet/rack/puppetmasterd/public/
+ <Directory /usr/share/puppet/rack/puppetmasterd/>
+ Options None
+ AllowOverride None
+ Order allow,deny
+ allow from all
+ </Directory>
+</VirtualHost>
diff --git a/ext/passenger/config.ru b/ext/passenger/config.ru
new file mode 100644
index 0000000..8608292
--- /dev/null
+++ b/ext/passenger/config.ru
@@ -0,0 +1,40 @@
+# Author: Christian Hofstaedtler <hofsta...@inqnet.at>
+# Copyright (c) 2007 Luke Kanies, 2008 Christian Hofstaedtler
+#
+# This file is mostly based on puppetmasterd, which is part of
+# the standard puppet distribution.
+
+require 'rack'
+require 'puppet'
+require 'puppet/network/http_server/rack'
+
+# startup code from bin/puppetmasterd
+Puppet.parse_config
+Puppet::Util::Log.level = :info
+Puppet::Util::Log.newdestination(:syslog)
+# A temporary solution, to at least make the master work for now.
+Puppet::Node::Facts.terminus_class = :yaml
+# Cache our nodes in yaml. Currently not configurable.
+Puppet::Node.cache_class = :yaml
+
+# The list of handlers running inside this puppetmaster
+handlers = {
+ :Status => {},
+ :FileServer => {},
+ :Master => {},
+ :CA => {},
+ :FileBucket => {},
+ :Report => {}
+}
+
+# Fire up the Rack-Server instance
+server = Puppet::Network::HTTPServer::Rack.new(handlers)
+
+# prepare the rack app
+app = proc do |env|
+ server.process(env)
+end
+
+# Go.
+run app
+
diff --git a/lib/puppet/network/http_server/rack.rb b/lib/puppet/network/http_server/rack.rb
new file mode 100644
index 0000000..801c9d1
--- /dev/null
+++ b/lib/puppet/network/http_server/rack.rb
@@ -0,0 +1,148 @@
+# Author: Christian Hofstaedtler <hofsta...@inqnet.at>
+# Copyright (c) 2006 Manuel Holtgrewe, 2007 Luke Kanies,
+# 2008 Christian Hofstaedtler
+#
+# This file is mostly based on the mongrel module, which is part of
+# the standard puppet distribution.
+#
+# puppet/network/http_server/mongrel.rb has the following license,
+# and is based heavily on a file retrieved from:
+# http://ttt.ggnore.net/2006/11/15/xmlrpc-with-mongrel-and-ruby-off-rails/
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+require 'puppet'
+require 'puppet/network/handler'
+require 'puppet/sslcertificates'
+
+require 'xmlrpc/server'
+require 'puppet/network/xmlrpc/server'
+require 'puppet/network/http_server'
+require 'puppet/network/client_request'
+require 'puppet/network/handler'
+
+require 'resolv'
+require 'rack'
+
+# A handler for a Rack-style puppet(master)d. For the most part, it works
+# exactly the same as HTTPServer::Mongrel:
+# After checking whether the request itself is sane, the handler forwards
+# it to an internal instance of XMLRPC::BasicServer to process it.
+module Puppet::Network
+ class HTTPServer::Rack
+ attr_reader :xmlrpc_server
+
+ def initialize(handlers)
+ @debug = false
+ if Puppet[:debug]
+ @debug = true
+ end
+
+ Puppet.info "Starting Rack server for puppet version %s" % Puppet.version
+ if Puppet[:name] != "puppetmasterd" then
+ Puppet.warning 'Rack server is not named "puppetmasterd", this may be not what you want. ($0 = %s)' % $0
+ end
+
+ @xmlrpc_server = Puppet::Network::XMLRPCServer.new
+ handlers.each do |name, args|
+ unless handler = Puppet::Network::Handler.handler(name)
+ raise ArgumentError, "Invalid handler %s" % name
+ end
+ h = handler.new(args)
+ @xmlrpc_server.add_handler(handler.interface, h)
+ end
+ Puppet.info "Rack server is waiting to serve requests."
+ end
+
+ # Validate a rack-style request (in env), and run the requested XMLRPC
+ # call.
+ def process(env)
+ # time to serve a request
+ req = Rack::Request.new(env)
+
+ if @debug then
+ Puppet.info "Handling request, details:"
+ env.each do |name, val|
+ l = " env: %s ->" % name
+ l = l + ' %s' % val
+ Puppet.info l
+ end
+ end
+
+ if not req.post? then
+ return [405, { "Content-Type" => "text/html" }, "Method Not Allowed"]
+ end
+ if req.media_type() != "text/xml" then
+ return [400, { "Content-Type" => "text/html" }, "Bad Request"]
+ end
+ if req.content_length().to_i <= 0 then
+ return [411, { "Content-Type" => "text/html" }, "Length Required"]
+ end
+
+ body = ''
+ req.body().each { |line| body = body + line }
+ if @debug then
+ Puppet.info "Request Body: %s" % body
+ end
+ if body.size != req.content_length().to_i then
+ if @debug then
+ Puppet.info "body length didnt match %d" % body.size
+ Puppet.info " vs. -> %d" % req.content_length().to_i
+ end
+ return [400, { "Content-Type" => "text/html" }, "Bad Request Length"]
+ end
+ info = client_info(env)
+ begin
+ data = @xmlrpc_server.process(body, info)
+ return [200, { "Content-Type" => "text/xml; charset=utf-8" }, data]
+ rescue => detail
+ Puppet.err "Rack: Internal Server Error: XMLRPC_Server.process problem. Details follow: "
+ detail.backtrace.each { |line| Puppet.err " --> %s" % line }
+ return [500, { "Content-Type" => "text/html" }, "Internal Server Error"]
+ end
+ end
+
+ private
+
+ def client_info(request)
+ ip = request["REMOTE_ADDR"]
+ # JJM #906 The following dn.match regular expression is forgiving
+ # enough to match the two Distinguished Name string contents
+ # coming from Apache, Pound or other reverse SSL proxies.
+ if dn = request[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
+ client = dn_matchdata[1].to_str
+ valid = (request[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
+ else
+ begin
+ client = Resolv.getname(ip)
+ rescue => detail
+ Puppet.err "Could not resolve %s: %s" % [ip, detail]
+ client = "unknown"
+ end
+ valid = false
+ end
+ info = Puppet::Network::ClientRequest.new(client, ip, valid)
+ return info
+ end
+ end
+end
+
--
1.5.4.3

Christian Hofstaedtler

unread,
Sep 25, 2008, 8:03:56 AM9/25/08
to puppe...@googlegroups.com

Christian Hofstaedtler

unread,
Sep 25, 2008, 5:31:43 PM9/25/08
to Puppet Developers
Tried mailing this 5 times or so but it didn't show up on the list,
now trying with the Google Groups web interface...

From 39cad0d23fe87baf3f8a591d7884e15b10004407 Mon Sep 17 00:00:00 2001
From: Christian Hofstaedtler <hofsta...@inqnet.at>
Date: Wed, 24 Sep 2008 10:07:38 +0200
Subject: [PATCH 1/1] Implement a Puppetmaster inside Passenger

Christian Hofstaedtler

unread,
Sep 25, 2008, 12:17:35 PM9/25/08
to puppe...@googlegroups.com

Christian Hofstaedtler

unread,
Sep 25, 2008, 5:58:25 PM9/25/08
to Puppet Developers
From 39cad0d23fe87baf3f8a591d7884e15b10004407 Mon Sep 17 00:00:00 2001
From: Christian Hofstaedtler <hofsta...@inqnet.at>
Date: Wed, 24 Sep 2008 10:07:38 +0200
Subject: [PATCH 1/1] Implement a Puppetmaster inside Passenger

+[1] http:///
+
+[2] http:///install.html
+
+[3] Passenger will not let applications run as root or the Apache
user,
+instead an implicit setuid will be done, to the user whom owns
+config.ru. Therefore, config.ru shall be owned by the puppet user.
+
+
diff --git a/ext/passenger/apache2.conf b/ext/passenger/apache2.conf
new file mode 100644
index 0000000..6a8a974
--- /dev/null
+++ b/ext/passenger/apache2.conf
@@ -0,0 +1,29 @@
+Listen 8140
+<VirtualHost *:8140>
+ SSLEngine on
+ SSLCipherSuite SSLv2:-LOW:-EXPORT:RC4+RSA
+ SSLCertificateFile /var/lib/puppet/ssl/certs/puppet-
server.inqnet.at.pem
+ SSLCertificateKeyFile /var/lib/puppet/ssl/private_keys/puppet-
server.inqnet.at.pem

Luke Kanies

unread,
Sep 26, 2008, 5:01:16 PM9/26/08
to puppe...@googlegroups.com
Hmm, I could have sworn I had commentary on this patch, but I can't
seem to find anything I disagree with. I guess it'd be nice to see
direct support in puppetmasterd for this.

It should be pretty straightforward to add support for it using the --
servertype switch, rather than using this config.ru file.

Otherwise, +1


--
Should I say "I believe in physics", or "I know that physics is true"?
-- Ludwig Wittgenstein, On Certainty, 602.
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://madstop.com

Christian Hofstaedtler

unread,
Sep 26, 2008, 6:46:50 PM9/26/08
to puppe...@googlegroups.com
I fixed the Puppet.warn thingie before posting.

Yeah, hm, I thought about doing all thatinside puppetmasterd, but I'm
not sure how this can integrate with passenger. You know,
puppetmasterd assumes it starts the process and then control the
http server, as opposed to having Apache start up and control/run the
http server and have Apache/passenger dispatch requests to puppet.

I was thinking that one could have a loader class, which can do "the
right thing" if it is supposed to be a standalone puppetmasterd or
an embedded puppetmasterd. As the support for 0.25.x is a lot more
than this patch (and config.ru is required so the app is recognized
as an app), I'd think this could wait 'til 0.25.x.
For 0.25.x I've prepared some stuff already, but nothing that works
for now :-/

What do you think?

Thanks,
Christian

* Luke Kanies <lu...@madstop.com> [080926 23:01]:

Luke Kanies

unread,
Sep 27, 2008, 3:36:32 PM9/27/08
to puppe...@googlegroups.com
On Sep 26, 2008, at 5:46 PM, Christian Hofstaedtler wrote:

> I fixed the Puppet.warn thingie before posting.
>
> Yeah, hm, I thought about doing all thatinside puppetmasterd, but I'm
> not sure how this can integrate with passenger. You know,
> puppetmasterd assumes it starts the process and then control the
> http server, as opposed to having Apache start up and control/run the
> http server and have Apache/passenger dispatch requests to puppet.
>
> I was thinking that one could have a loader class, which can do "the
> right thing" if it is supposed to be a standalone puppetmasterd or
> an embedded puppetmasterd. As the support for 0.25.x is a lot more
> than this patch (and config.ru is required so the app is recognized
> as an app), I'd think this could wait 'til 0.25.x.
> For 0.25.x I've prepared some stuff already, but nothing that works
> for now :-/
>
> What do you think?


Duh, I forgot that this runs within Apache.

Nevermind about what I said about including it in puppetmasterd.

+1

--
The trouble with the world is that the stupid are cocksure and the
intelligent are full of doubt. -- Bertrand Russell

Reply all
Reply to author
Forward
0 new messages