August 2010 Archives

Running Parley with fastcgi

Today I hope to show you how to run Parley under fastcgi.

If all goes well I’ll have a publically visible message board by the end of the post.

I’m assuming you’ve already installed Parley.

For this entry you’ll need to have acess to a user with sudo superpowers.

Create a new site

First we’ll add a new site to the apache configuration:

sudo vim /etc/apache2/sites-available/parley.named_vhost

and add the following:

<VirtualHost *:80>
  ServerName              parley.pl

  DocumentRoot            /home/parley/perl5/lib/perl5/Parley/root
  Alias           /static /home/parley/perl5/lib/perl5/Parley/root/static
  Alias           /       /home/parley/perl5/bin/parley_fastcgi.pl/

  FastCgiServer           /home/parley/perl5/bin/parley_fastcgi.pl -processes 3

  # stuff that's good to have
  ServerAdmin         carer@parley.pl
  ErrorLog            /home/parley/parley/parley.pl/log/error.log
  CustomLog           /home/parley/parley/parley.pl/log/access.log common
</VirtualHost>

Save the file, and create a folder we’ll need:

sudo install -d -o parley -g parley /home/parley/parley/parley.pl/log/

Enable the site:

sudo a2ensite parley.named_vhost
sudo /etc/init.d/apache2 reload

Start the Email Engine

If you want activation emails to be processed you’ll need to start the email processing daemon:

# as 'parley' user
parley_email_engine.pl

A Quick Hack

For a reason I’ve yet to determine, I was seeing an error in the logs when I reloaded apache:

[Fri Aug 13 16:37:53 2010] [warn] FastCGI: server "/home/parley/perl5/bin/parley_fastcgi.pl" restarted (pid 4758)
Can't locate Parley.pm in @INC (@INC contains:
    /home/parley/perl5/bin/../lib /etc/perl ...)
    at /home/parley/perl5/bin/parley_fastcgi.pl line 15.

I hacked this by editing /home/parley/perl5/bin/parley_fastcgi.pl and adding the perl5 line:

use FindBin;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../lib/perl5";
use Parley;

I’m sure I’ve done something stupid, but for now … it’ll do.

Allowing User Avatars

Until I find a better way of doing this (i.e. using gravatar like I did with cleavag.es) you’ll need to make a writable directory for user avatars:

sudo install -o www-data -g parley -m 0770 -d ~parley/parley/parley.pl/user_files
ln -s $HOME/parley/parley.pl/user_files /home/parley/perl5/lib/perl5/Parley/root/static/user_file

Not Perfect

I know there are still areas where Parley needs some work. It’s been left, neglected, in a box for a year.

It’s usable, and now - finally - has a public demo.

The Application

You should be able to explore Parley by visiting parley.pl in your browser.

Installing Parley

This article is a simple guide to installing and running Parley on a remote/virtual server. It doesn’t cover modifiction, extension and configuration. I hope to cover this in a separate entry.

I’ve been meaning to write this for some time, partly inspired by passing comments from people who’ve tried but found it too difficult or confusing.

Pre-requisites

  • Linode server
  • Ubuntu installed (9.10?)
  • User account: parley

Guide written using perl v5.10.0 (yes, I know!)

Use screen

screen
sudo su - parley

Install local::lib

mkdir -p $HOME/parley/{parley.pl,sandbox}
cd $HOME/parley/sandbox/
wget http://search.cpan.org/CPAN/authors/id/G/GE/GETTY/local-lib-1.006005.tar.gz
tar zxf local*gz
cd ./local*
perl Makefile.PL --bootstrap
make test && make install
echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc
source ~/.bashrc

Install Parley

cpanp
s conf prereqs 1; s save
install Parley

Keep half an eye on it, but expect a reasonable wait while the dependencies are installed.

Set::Object

I had some problems with Set::Object

CPAN Terminal> i Set::Object

Installing Set::Object (1.28)
WARNING: This key is not certified with a trusted signature!
Primary key fingerprint: 8231 2E41 472B 5F8D 86E3  6E30 FC06 4088 66B2 5843
--- SIGNATURE Thu Jul 22 07:19:46 2010
+++ (current) Tue Aug 10 17:39:30 2010
@@ -1,5 +1,6 @@
SHA1 9083e3c7f3b247405b838cea67278b7684e36e8d Changes.pod
-SHA1 816639c05c69373b63a93333c3e7e60a87866e56 MANIFEST
+SHA1 6825ef505c910d011772d0365a43b1c8de6eb503 MANIFEST
+SHA1 b0da4e4c2b100da7030708dabbbc6485d7832387 META.yml
SHA1 c826cfdec5efc768c4a6eaec8d690b4f309c03d0 Makefile.PL
SHA1 8e8a877750f1f3fbdc5240a86246ff4399c1184f Object.xs
SHA1 5df26a8f141049c2a8c277417af071782808300b README
==> MISMATCHED content between SIGNATURE and distribution files! <==
[ERROR] Signature check failed for module 'Set::Object' -- Not trusting this module, aborting install

If you trust it:

z Set::Object
perl Makefile.PL
make test && make install
exit

Run Parley - errors expected

We can check that we’ve got an installed application with:

CATALYST_DEBUG=1 parley_server.pl

Then pointing elinks (in another screen window) at our app. We are expecting database connection errors:

elinks http://localhost:3000

Set-Up The Database

You’ll need a database for the application to use:

Modify ACL

You will probably need to add something like this to your pg_hba.conf:

host  parley      parley      127.0.0.1/32          trust
local parley      parley                            trust

Exact details are for you to decide but the above allows quick, local-only access to the database.

Don’t forget to reload your database:

sudo /etc/init.d/postgresql-8.3 reload

Create the database

As a user with sudo privileges:

sudo -u postgres createuser -A -R -d parley
createdb -U postgres -O parley -E UTF8 parley
psql -U parley -d parley -f ~parley/perl5/lib/perl5/Parley/db/parley.psql

View The Application

If you now view

elinks http://localhost:3000

you should see a text-only view of the main Parley page:

elinks.png

If you aren’t stuck behind an evil proxy you should also be able to view the application in your browser, by visiting myserver:3000

Still To Come

  • running under fastcgi
  • tweak the configuration
  • Google Ads
  • … and anything else I’ve forgotten

Once I have the application running under fastcgi I’ll share the URL for general exploration and evaluation.

HACK HACK BODGE

Following on from a conversation at the Pisa-London.pm Social last night about vim syntax highlighting useful words in perl files like TODO and how it might also be useful to highlight other useful words, like HACK and BODGE, I decided to have a go.

I knew the initial solution would be fairly simple - hack /usr/share/vim/vim72/syntax/perl.vim.

That seemed to easy, so I investigated a $HOME/.vim/ solution.

Initially I copied the existing perl.vim into my local directory:

cp /usr/share/vim/vim72/syntax/perl.vim $HOME/.vim/syntax/

edited the perlTodo line to include the new tokens.

I opened my test file and it worked!

Going Further

I’ve had a long-standing urge to handle tokens followed by an evil colon. I prefer:

# TODO: something shiny

over

# TODO something shiny

To me it looks nicer when it isn’t highlighted.

I further modified the perlTodo line, from keyword to match and included my friend, the colon.

One “:e!” later and … it worked!

Cleaning Up

I really didn’t want a copy of the entire perl.vim syntax file.

I took a risk and edited my local copy down to one single line, reloaded my test file and … it did the right thing!

The Solution

To go from:

perl.vim.before.png

to:

perl.vim.after.png

create $HOME/.vim/syntax/perl.vim and add the following line:

syn match perlTodo    "\<\(TODO\|TBD\|FIXME\|XXX\|HACK\|BODGE\)\:\?\>" contained

Sorted!

It's Easy To Mock

Recently there were cries in the office of:

oh noes! $thingy, which we rely on but don’t control, no longer has a hard-coded, specific record upon which we rely for one of our application tests

Miraculously I had a free slot in my calendar, donned my cape, took off my horn-rimmed glasses and wore my underpant outside my jeans:

I’ll have a look at that for you guys!

Buried Deeply … Somewhere

It turns out that our test was distanced from the problematic remote call by at least one intermediate “helper” module:

our_test.t:

# ...
use Test::OurApp::Data;

# ...
my $thing = Test::OurApp::Data
    ->get_thingy_from_xml( $file );

Test/OurApp/Data.pm:

# ...
use OurApp::ThingyImporter;

# ...
sub get_thingy_from_xml {
    # ...
    $result = import_thingy_ok(
        # ...
    );
    # ...
}

# ...
sub get_thingy_from_xml {
    # ...
    $result = OurApp::ThingyImporter::process_thingy_xml(
        # ...
    );
    # ...
}

OurApp/ThingyImporter.pm:

# ...
sub process_thingy_xml {
    # ...
    $service = OurApp::Domain::Helper->new(
        # ...
    );
    $result = $service->our_annoying_method(
        # ...
    );
    # ...
}

Don’t spend too long worrying about the exact path through the code, just notice that our test is a long way from our_annoying_method()

There wasn’t an obvious or easy way to alter the code to say

We’re testing something else, we don’t care too much about the results

without evil things like test_mode => 1 being passed through the code-tree. Messy and horrible.

Mocking

I’ve heard about mocking objects over the years but have never found a case for using it … until now.

I decided it was time for another look at Test::MockObject.

A short investigation revealed that our_annoying_method() returned a hashref of data used by the rest of the tests … and the tests didn’t care about most of the values.

All I needed to do was inject a method that subverted the problematic method call.

The Solution

The solution was far easier than I anticipated. I wrote a new module, living under t/lib

package Test::OurApp::Mock::Thingy;
use Moose;
    extends 'OurApp::Domain::Thingy';

use Test::MockObject;

# override the troublesome method - we don't really need
# to worry about actual lookups, we just need some data to work with
sub our_annoying_method {
    my $self    = shift;
    my $data    = shift;

    # we don't really care what's returned
    # as long as it has valid looking data
    my $result = {
        requiredData        => $data->{reference}||'CARROT';
        # ...
    };

    return $result;
}

# use Test::MockObject to inject our own method
my $mock = Test::MockObject->new;
$mock->fake_module(
    'OurApp::Domain::Thingy',
    our_annoying_method => \&our_annoying_method,
);

1;

All that was then required was one extra line early in our troubled tests sctipt:

use Test::OurApp::Mock::Thingy;

Tests no longer rely on specific data in someone else’s remote service. Tests pass. Developers happy. Success.

About Chisel

user-pic I blog about Perl.