Begin main content

supervisord supervisorctl cheat sheet

On my new server I made the switch from daemontools to supervisor. As if to make daemontools users feel at home the documentation for supervisorctl use is a bit thin :)
So far my biggest gotcha was that after adding a new .conf file in your includes (or to the main file itself, but you wouldn't do that would you?) is that you need to do *both* of the following:

> supervisorctl reread
new.app.conf: available
> supervisorctl update
new.app.conf: added process group
> supervisorctl
new.app         RUNNING ...

 

haproxy

Unfortunately supervisor doesn't offer a way to provide a custom restart command, so doing an uninterrupted haproxy restart via supervisor isn't possible. Instead make sure you have autorestart set to unexpected (the default) rather than true (which is what I usually do) - that way if you want a clean haproxy restart you can just do it yourself at the commandline using the -sf option as normal.

11:14 PM, 25 Mar 2012 by Mark Aufflick Permalink | Comments (0)

SAPI Cocoa SDK

The Cocoa Sensis SAPI SDK is live, ready for this weekend's Sensis SAPI hackathon. https://github.com/pumptheory/SAPI-Cocoa-SDK

SAPI LogoYellow Pages Logo

01:13 AM, 24 Mar 2012 by Mark Aufflick Permalink | Comments (0)

Stunnel + Thin + Rails for the world's easiest ssl hosting

These days I do most quick and dirty web stuff with Ruby on Rails, and any open source web stuff I install I prefer Rails based code for easy hacking. Every so often you want to host something for internal or other small-volume usage, but it has to be SSL. Traditionally this is a pain in the backside, especially with Rails. Back in the day I did everything with OpenACS or plain AOLServer. This meant I had to install a bunch of stuff by hand (although debian packages are now available), but once it was done it was a simple config tweak to change the number of threads and/or add ssl etc. With Rails it's kind of the opposite. Getting things up and running is incredibly easy, but scaling it or adding ssl usually means Apache, or Nginx, or some other (relatively) heavy server plus other stuff. Doing this all as a non-super user is even more painful.

For a client I wanted to setup a Redmine instance for a wiki and browsing internal git repositories. It's a Rails 2.x app. Initial setup is easy. Using the latest trunk version of Redmine (which supports Ruby 1.9 and uses bundler) it's a simple matter of the following steps (which assume pretty much nothing is installed except base libraries like sqlite3):

  • checking out the svn trunk

svn co svn co http://redmine.rubyforge.org/svn/trunk redmine
cd redmine

  • installing rvm, setting up the right ruby & gem set

bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
. ~/.bashrc
rvm install ruby-1.9.3
rvm use ruby-1.9.3@redmine --create
rvm install bundler

  • installing bundler and using it to prepare all the ruby gems (I am using sqlite and don't have mysql libraries installed)

gem install bundler
bundle install --without=mysql

You now have Redmine up and running, via the test webrick server, on port 3000. But that's no good for two reasons, one we obviously don't have ssl, and two webrick is a single process (and ruby is always a single processor thread) so it's not very scalable.

A nice simple, and yet fast, way to scale Ruby http servers is Thin. It's Ruby and C. It's only http though, so we need to put ssl in front some how. A great way of doing this is stunnel, which can tunnel just about anything to anything when it comes to ssl. So we run a couple of Thin instances, and stunner to proxy it to ssl. The great thing is we can arrange for the communication between the two to be via Unix sockets so we don't even need to reserve localhost TCP ports so we can scale the number of instances without checking with anyone else.

Here are my steps for Thin and stunnel:

  • Install Thin:

gem install thin

  • Install stunnel:

# get the latest version of stunner from http://www.stunnel.org/?page=downloads
tar zxf stunnel-4.xx.tar.gz
cd stunnel-4.xx
mkdir ~/usr 
./configure --prefix=~/usr
make
make install

  • You need a .pem certificate for stunnel. If you don't have a real certificate, you can create a self-signed one like so:

openssl req -new -x509 -days 365 -nodes -config stunnel.cnf -out stunnel.pem -keyout my_stunnel.pem

  • where the stunnel.cnf file is in the source distribution. Answer the questions appropriately.
  • stunnel needs a config file, something like this (in this case for three thin instances)

pid =
cert = /path/to/my_stunnel.pem

[redmine]
accept = 12345
connect = /path/to/my_rails_app/tmp/thin.0.sock

connect = /path/to/my_rails_app/tmp/thin.1.sock

connect = /path/to/my_rails_app/tmp/thin.2.sock

  • start up stunnel

~/usr/bin/stunnel /path/to/my/stunnel.conf

  • start up your rails app with Thin

thin start -s3 --socket /path/to/my_rails_app/tmp/thin.sock -e production

And that's it, your site running on https port 12345! All this has not required root access at any point. If you want to listen on a low port, eg. 443, the only thing that needs to run as root is stunnel.

But don't break out the champagne yet - we have a problem. Your rails app knows the hostname and port thanks to the Host: header, but it has no idea that it's running behind stunnel and is therefore ssl. This is only a problem in the occasions where a full url is needed, and the primary case is for http redirect headers. I take care of this by rewriting the Location header in application_controller.rb:

after_filter :force_https_for_redirects
def force_https_for_redirects
if response.headers.has_key?("Location")
response.headers["Location"].sub!(/^http:/, 'https:')
end
end

You may have other cases that need fixing, like constructing urls for emails. Note that I wouldn't recommend mucking about with the X-Forwarded-Proto patches for stunnel. I just don't trust third party patches for security software, and in any case I'm not sure it would work with using Unix sockets for the intermediary transport.

Update: Here's how to monkey patch ActionController::UrlWriter::url_for() so your emails will have correct links. In Rails 2 (in my case for redmine), I did it in environment.rb - for Rails 3 I think you could do it in application.rb, but it doesn't really matter where you do it as long as it gets compiled after ActionController::UrlWriter is loaded.

module ActionController
module UrlWriter
alias :original_url_for:url_for
def url_for(options = {})
options[:host] = 'yourhost.com'unless options[:host]
options[:protocol] = 'https' unless options[:protocol]
options[:port] = 7022 unless options[:port]

original_url_for(options)
end
end
end

Another update: There's another patch you need to make in the redmine code itself, in app/controllers/application_controller.rb, make the following change to the require_login method, adding in the :protocol => 'https://'. This is required since it doesn't use url_for to generate the redirect url.

respond_to do |format|
    format.html { redirect_to :protocol => 'https://', :controller => "account", :action => "login", :back_url => url }
    format.atom { redirect_to :protocol => 'https://', :controller => "account", :action => "login", :back_url => url }

09:12 PM, 20 Mar 2012 by Mark Aufflick Permalink | Comments (0)

PMPKVObservation – Yet Another KVO-improvement project

If you’re reading this then you’re probably as frustrated by seemingly random KVO crashes and/or the pain of huge if/else blocks in your observers. I’ve never been happy with the other KVO-improvement classes I’ve seen, and never having had any bright insights myself I kept doing things the normal way. This becomes especially painful with things like view based NSTableViews when you are re-using objects and so need to observe a new object, being very careful to un-observe the prior object (unless it’s been released, which you need to either track yourself if you can, or retain it, which has its own problems).


It was clear that the dealloc swizzling approach of Mike Ash’s MAKVONotificationCenter was unavoidable, but I didn’t like the complexity. Recently Gwynne Raskind posted a somewhat updated MAKVONotificationCenter which sparked some discussion, including a comment discussing SPKVONotificationCenter by Joachim Bengtsson. Joachim’s brainwave was that observations should be modelled as standalone objects and simply managing the lifecycle of that object appropriately should remove the observation. Clean and simple.

Except it’s not quite that simple because you still need to swizzle the dealloc of the observed object since it can go away at any time. And as much as I love a good macro as much as the next hacker, Joachim’s $depends() macro looks about as much fun as a turing complete makefile.

Enter PMPKVObservation!

Include PMPKVObservation.m and .h in your project, then do something like:

#import"PMPKVObservation.h"

@interface PMPKVOTests ()
@property (retain) PMPKVObservation * kvo;
@end

@implementation PMPKVOTests
@synthesizekvo = _kvo;

- (void)observationFired:(PMPKVObservation *)observationchanges:(NSDictionary *)changes;
{
NSLog(@"observation fired for object: %@ keyPath: %@ changes: %@",
observation.observee,
observation.keyPath,
changes);
}

- (void)selectorObservation
{
self.kvo = [PMPKVObservation observe:anObjectToObserve
observer:self
selector:@selector(observationFired:changes:)
keyPath:@"observeMe"
options:0];
}

- (void)blockObservation
{
self.kvo = [PMPKVObservation observe:anObjectToObserve
keyPath:@"observeMe"
options:0
callback:^(PMPKVObservation *observation, NSDictionary *changeDictionary) {
NSLog(@"observation fired for object: %@ keyPath: %@ changes: %@",
observation.observee,
observation.keyPath,
changes);
}];
}

- (void)dealloc
{
[ _kvo release];

[super dealloc];
}

@end

The options and change dictionary are as per normal KVO. You need to be wary of the block causing retain cycles of self as usual.

Unlike MAKVONotificationCenter and others, you are responsible for managing the lifecycle of the kvo object – when it is dealloc-ed the observation will be removed. Like MAKVONotificationCenter, a minimum of magic is used to swizzle the dealloc method of the observed object and remove the observation if it still exists (tracked via an associated NSHashTable). If for some reason you want to find out if the kvo object you hold has been released early you can check the isValid accessor (which you can observe with KVO).

Caveats

  1. While I am using this in a client project, that project has not yet shipped so I can’t promise wide-spread testing. Take a look at the tests in the test app and if you are using scenarios that you don’t thing are tested pull requests are welcome!
  2. I haven’t tried this under ARC, but I think I’ve made PMPKVObservation.m so it will compile and work as-is (the same can’t be said for the test app). Please let me know how you go.
  3. No attempt is made to stop you changing the observed object etc. after creation, but doing so isn’t going to be very effective…

Repository: https://github.com/aufflick/PMPKVObservation

06:49 PM, 13 Mar 2012 by Mark Aufflick Permalink | Comments (0)

XML

Blog Categories

software (41)
..cocoa (23)
  ..heads up 'tunes (5)
..ruby (6)
..lisp (4)
..perl (4)
..openacs (1)
mac (21)
embedded (2)
..microprocessor (2)
  ..avr (1)
electronics (3)
design (1)
photography (26)
..black and white (6)
..A day in Sydney (18)
..The Daily Shoot (6)
food (2)
Book Review (2)

Notifications

Icon of envelope Request notifications

Syndication Feed

XML

Recent Comments

  1. Mark Aufflick: Re: the go/Inbox go/Sent buttons
  2. Unregistered Visitor: How do make a button to jump to folder
  3. Unregistered Visitor: Note I've updated the gist
  4. Unregistered Visitor: umbrello is now an available port on macPorts
  5. Unregistered Visitor: Updated version on Github
  6. Unregistered Visitor: Modification request.
  7. Unregistered Visitor: Accents and labels with spaces
  8. Unregistered Visitor: Mel Kaye - additional info
  9. Unregistered Visitor: mmh
  10. Mark Aufflick: Thank you