Toadfarm on Base Debian: An absolutely minimal multi-tenant webserver

Here we create an absolutely minimal multi-tenant webserver, without even installing Apache or NginX. Although we can add either of those later, with our content running under them as reverse proxies, this tutorial lets you run one or more Mojolicious “apps” mounted under a single toadfarm startup script, saving you the “default perl memory” times the number of worker processes and apps.

We will b using Jan Henning Thorsen’s Toadfarm:

Toadfarm is a module for configuring and starting your Mojolicious applications. You can either combine multiple applications in one script, or just use it as a init script.


First, perform a Debian Netinstall on a virtual machine or virtual host. The only modification to all the default selections is to enable only “Standard System Utilities” and disable desktop, database, mail, print, file, and web server. We will be building our own of all those!

Now boot up into that absolutely stock, base machine. For illustration, we will assume your username is gronk − change this as necessary. First let’s install a few system packages (ssh for access, curl for installing Perlbrew et al, sudo for convenience, and the no-X version of emacs because I’ve been using it since 1980):

$ su
# apt-get install sudo ssh curl emacs23-nox
# usermod -a -G sudo gronk
# exit

Now we install our Perlbrew environment as the user:

$ \curl -L http://install.perlbrew.pl | bash
$ echo source ~/perl5/perlbrew/etc/bashrc >> ~/.bash_profile
$ perlbrew install 5.20.2 -j5

The -j5 means use five processes for the Make. Then:

$ perlbrew switch 5.20.2
$ perlbrew install-cpanm
$ curl -L https://cpanmin.us | \
perl - -M https://cpan.metacpan.org -n Mojolicious
$ cpanm Toadfarm

jhthorsen explains how this goes together:

You can’t run individual apps inside toadfarm as different user, but you can start toadfarm as root and change to a different user. This is true of Mojolicious generally.

In particular, we create an Init script with a #! (hashbang) that points to our user’s “brewed” Perl. From the documentation:

Remember that the hashbang can be anything, so if you have Toadfarm and Mojolicious running under plenv or Perlbrew you need to change the hashbang part…

So we change our Init script to start with:

#!/home/gronk/perl5/perlbrew/perls/perl-5.20.2/bin/perl

Then in the Toadfarm script called by the Init script, which is started as root, we do the switch to our user (called some-www-user in the documentation, gronk here):

#/usr/bin/env perl
use Toadfarm -init;
# …
start [qw( http://*:80 https://*:443 )], user => "gronk", group => "www";

From the documentation:

Changing user has one implication: The workers will not use some-www-user’s secondary groups. So if “some-www-user” is part of the “www” and “db” groups, then the process will only be run as “some-www-user” part of the “www” group.

See also the IRC log for 26 April 2014.

The process of writing a Mojolicious plugin

I have gotten far enough into Mojolicious development to feel rather baffled again. This post is a work in progress, to be edited and filled in as I discover the answers.

According to the Rendering guide,

A skeleton for a full CPAN compatible plugin distribution can be automatically generated.

We are going to create a plugin called StaticText, so let’s do:

$ mojo generate plugin StaticText

What that actually does is the following actions inside your current directory, as we can see from its output log:

  [mkdir] ./Mojolicious-Plugin-StaticText/lib/Mojolicious/Plugin
  [write] ./Mojolicious-Plugin-StaticText/lib/Mojolicious/Plugin/StaticText.pm
  [mkdir] ./Mojolicious-Plugin-StaticText/t
  [write] ./Mojolicious-Plugin-StaticText/t/basic.t
  [exist] ./Mojolicious-Plugin-StaticText
  [write] ./Mojolicious-Plugin-StaticText/Makefile.PL

Q: How exactly can I develop this inside an example application? The documentation’s standard load procedure:

$self->plugin('Mojolicious::Plugin::StaticText');

fails because it doesn’t look in Mojolicious-Plugin-StaticText/lib/Mojolicious/Plugin/ of course.

Q: How do I install my common personal plugins into my individual “apps” ? Presumably I should be able to “git checkout” them directly into… lib/Plugin/ …? Obviously I’m not going to edit them into the MyApp:: namespace, right?

Q: Should use the Mojolicious::Plugin namespace for plugins that I consider to be eventual candidates for CPAN, or what is best practice for naming my personal plugins that I plan on using across multiple projects?

Q: I see how to pass parameters when loadiing a plugin, but does each plugin get loaded, or registered, just once, or can I have multiple instances of a plugin?

NOTE: Refer also to the Plugins document

Q: Where do I store “instance data” that is computed from the configuration parameters I pass when loading a plugin?

A: Plugins are simply modules, not objects. If we want to save configuration data at load-time, we could save that in an attribute of the application like this: $app->attr(‘some_attribute_name’ => value) which we later access as just “$app->some_attribute_name”.

A good example of how configuration parameters are passed, handled, and saved is http://search.cpan.org/~madcat/Mojolicious-Plugin-Database/lib/Mojolicious/Plugin/Database.pm

Behind the curtain: when you call attr, that actually builds and then eval(s) a string which defines a function by the supplied name. That function optionally sets (if called with a value), and always returns the value of the named key in the object upon which you originally called ->attr(). So in the case of doing $app->attr(‘foo’) the function would create and use $attr->{‘foo’}.

Q: The Mojolicious::Plugins guide shows the example code

$plugins->register_plugin('MyApp::Plugin::SomeThing', Mojolicious->new);

below the presumably required code:

use Mojolicious::Plugins;

my $plugins = Mojolicious::Plugins->new;
push @{$plugins->namespaces}, 'MyApp::Plugin';

Yet elsewhere, for example in http://mojolicio.us/perldoc/Mojolicious/Plugin/JSONConfig ,  we see a completely different style that runs with application start:

sub startup {
  my $self = shift;
  $self->plugin('Mojolicious::Plugin::StaticText');

What exactly is the difference between these two?

Q: In the version with

$plugins->register_plugin('MyApp::Plugin::SomeThing', Mojolicious->new);

what does the Mojolicious->new do? According to the documentation for Mojolicious->new(), that should “Construct a [whole other] new Mojolicious application and call ‘startup’… set up logging… the renderer, static file server, default set of plugins…” We can’t seriously be loading a whole new “app” nested inside of our current “app” can we? What’s going on?

Q: After the name of the plugin, what happens to the remaining arguments to $self->plugin()?

A: The optional second argument must be either a reference (to a scalar, array, hash, subroutine, etc.) or a scalar. If it’s just a plain scalar such as 3, like the plugin’s register() subroutine will be called with a reference to a hash like this: {3, undef}. In general, you will probably want to pass a reference to a hash that contains your configuration parameters.

Mojolicious: An interview with author Sebastian Riedel

We are experiencing Perl’s most successful period since the 1990s. I-Programmer spoke with Sebastian Riedel, originator of the relatively new Mojolicious system built on Perl.

…The truth is that installing Mojolicious is simply a very fast and pleasant experience… we’ve done with tight integration of WebSockets and event loops, [and] the ability to grow from single-file prototypes to well structured web applications.

The first example application you encounter on our website… doesn’t look very complicated at all. But once you start digging a little deeper, you’ll quickly realize how crazy (in a good way) it really is, and how hard it would be to replicate with any other web framework, in any language…

Read the rest of the story at i-programmer, 11 December 2014.

Mojo: Content boxes like “Widgets”

When we create a sidebar, generally we would like to suppress emitting the wrapper and title of our “widgets” (yes, I am still coming from the view of a developer too long having done nothing but WordPress) when there is no content “in the box.”

In code, we can examine the currently defined stash data or content areas like this:

if (length($c->content('content')) { … }

Note that, at least as of Mojolicious 6.0, content() will actually create an empty content area even if not given any content, so we must test length(); for stash data, we probably would use defined instead.

We can do this inside a template too. Here’s an example for both content and stash:

#!/usr/bin/env perl

use Mojolicious::Lite;

# setup base route
any '/' => sub {
  my $self = shift;

  # Example stash data and content
  $self->stash( text2 => 'some text' );
  $self->content( area3 => 'some text' );
  $self->render('index');
};

app->start;

__DATA__

@@ index.html.ep

<!DOCTYPE html>
<html>
<head><title>Widget Boxes</title></head>
<body>

  % if (defined stash('text1')) {
      <b><%= stash('text1') %></b>
  % } else {
      <em>No content</em>
  % }

<hr width='50%'>
  % if (defined stash('text2')) {
      <b><%= stash('text2'); %></b>
  % } else {
      <em>No content</em>
  % }

<hr>

  % if (length content('area1')) {
      <b><%= content('area1') %></b>
  % } else {
      <em>No content</em>
  % }
<hr width='50%'>

  % if (length content('area2')) {
      <b><%= content('area2') %></b>
  % } else {
      <em>No content</em>
  % }
<hr width='50%'>

  % if (length content('area3')) {
      <b><%= content('area3') %></b>
  % } else {
      <em>No content</em>
  % }

</body>
</html>

Zero to Mojolicious, Part 3: Using External Content from WP-API

Last time, we created a site_design template for Mojolicious which built on a basic layout template for Zurb Foundation. On top of this we can use our content-specific templates, with the two lower templates nested below.

Here’s an example that uses content from a WordPress™ Post. The simplest way to retrieve the actual content of just a post from WordPress is to use the rather new WP-API. This was to be part of WP core in their version 4.1, and although its appearance in core has been delayed, can be installed as the “WP REST API” plugin from the WP repository.

Once the WP-API plugin is enabled, we can request a URI like one on this site as:

http://blog.wlindley.com/wp-json/wp/posts/1265

That will return a JSON result with the rendered HTML (WordPress stores post and page content in the database with newline breaks instead of paragraph tags, and an assortment of other changes we do not want to deal with here) as well as a variety of metadata about the post. Unfortunately the current WP-API plugin does not let us request by post name, only by internal ID. One hopes the API will be more complete when it is fully released. Also beware the URI and request schema may differ in a final release.

We can use Mojo::UserAgent to retrieve the remote content and parse its JSON.

In a new file lib/MyApp/Controller/ then we add a controller. We use the rendered HTML versions for the content, title, and excerpt, while copying the other values with unmodified keys all to the stash, which we can then reference in our template. The two templates notfound and nopage (not shown here) are used when things go wrong.

package MyApp::Controller::Blogpage;
use Mojo::Base 'Mojolicious::Controller';

use Data::Dumper;
use Mojo::UserAgent;

# This action will render a template
sub retrieve {
  my $self = shift;

  my $ua = Mojo::UserAgent->new;

  my $id = $self->param('id');

  if (defined $id) {
      $id =~ s/\D//g; # remove all non-digits
  }
  if (!$id) {
      $self->redirect_to('notfound');
      return;
  }

  my $tx = $ua->get("http://blog.wlindley.com/wp-json/wp/posts/${id}");

  if ($tx->success) {
      my $value = $tx->res->json;

      # Render template "blogpage/retrieve.html.ep" with
      # values from WP-API
      $self->render((map { $_ => $value->{$_}->{rendered} }
                           qw/content title excerpt/) ,
		    (map { my $vname = $_;
			   $vname =~ s/^format\Z/wp_format/;
			   $vname => $value->{$_} }
                           qw/date type format comment_status id modified
				ping_status featured_image author sticky
                                excerpt slug guid link/) );
  } else {
      $self->redirect_to('nopage');
  }  
}

1;

and create a template in templates/blogpage/retrieve.html.ep. Note how we are using the site_layout template from last time:

% layout 'site_layout';
% title "$title";
<h1><%= $title =%></h1>

<blockquote>Published on <%= $date %></blockquote>
%== $content

Of course you can use any of the metadata tags which we copy in the controller (featured_image might be an interesting one).

Then in our MyApp.pm we add this into the startup subroutine:

$r->get('/blog')->to('blogpage#retrieve');

Now we can visit http://localhost:3000/blog?id=1265 and you should see the content of the WordPress post, dropped into the content section that you made in the Foundation style theme from last time.

Next time, we still plan to access a database.

Testing Mojolicious locally

So you have coded your newest web system in Mojolicious and would like to test it in an environment where it “thinks” it’s running on the actual webserver, even though it’s still running on your machine.

Add your www.example.com entry to point to 127.0.0.1 in /etc/hosts and then redirect your localhost’s port 80 to port 3000:

sudo iptables -t nat -I OUTPUT -p tcp \
-d 127.0.0.1 --dport 80 \
-j REDIRECT --to-ports 3000

No need to run as root!

A Bad Day for Freedom, Science, and Technology

“Net Neutrality” sounds good, like Swiss chocolate.  But…

Now the FCC will begin to tax the Internet and dictate how the Web develops.

Remember Ma Bell?

Telephone answering machines were invented in the 1930s but only introduced to the public in the 1970s, because it was not permitted by Tariffs and other Regulations.

Packet switching, which is the foundation of the Internet, was invented in the late 1950s but held back from wide use until the late 1980s, because it was not permitted by Tariffs and other Regulations.

Government over-regulation held back the Internet for half a century!  Imagine what America could have been if we had the Web in the 1960s.  But we didn’t, because of the FCC and its friends.

Mark my words: This week’s ruling spells the end of freedom and quashes the development of science and technology.

Be careful what you wish for.

Zero to Mojolicious, Part 2: Content-Wrapping Filter Templates

In the previous installment, we built a basic site with Zurb Foundation.

We were able to split the main HTML wrapper into a layout file, but our index.html that we passed to the render function had to have the whole rest of the row and column divisions. We really want to just have our “content” consist only of the body of each page, and let the template system take care of the row/column site structure and any navigation or sidebars.

This proved far more challenging than I expected when first exploring Mojolicious.

Maybe just because I had tried, I really tried to learn Ruby on Rails; I had attended numerous Meetups, looked at plenty of code, read several books, and even worked on a project or two. But all that code looked more like wishful thinking, or dependence on “magic” as a crutch, than code crafted by folks who understand how all the bits really work behind the curtain. I spent more time ripping apart Rails and being frustrated at Ruby’s zaniness (zero is true!) than I did actually getting anything done.

Glen Hinkle (tempire) explains this well in a post to the Mojolicious group [groups.google.com, 11 November 2011]:

This is a matter of the tools built on top of the platform, rather than the platform itself. Ruby’s Rails distributes these sort of tools and touts them as the hotness, but in practicality, they don’t provide much value…

Let’s say you have a tool that creates your CRUD interface and boilerplate. It looks great, because look at all the work it saved you from doing! In reality, it’s saved you nothing. When you customize your app, you’re going to have to re-organize and/or re- write every piece of code/HTML. Guaranteed. These tools are a red herring – they’re simply not going to save you any time at all.

For example: You create a resource. Oh, but you need to verify the data. Except, how you verify depends on the nature of your data. That’s ok, you can just take out the boilerplate and put your own code in. Except, it ties in with the way it stores data in the database. That’s ok, you can replace that with your own code. Except, that ties in with the way you’ve chosen to display your data. That’s ok, you can replace the templates with your own code. Except, you need to show your templates in a specific way so that it makes sense. That’s ok, you can replace…

In the end, boilerplate templates limit you more than save you time…

Attempt to create boilerplate on any platform, and you’ll see how useless it is after the 3rd web app, wherein maintaining the boilerplate was more effort than creating the app itself. If it’s not, you don’t actually want a custom web app, you want a CMS.

Once I realized that Mojo is just Perl inside, and all the idioms are just old-fashioned syntactic sugar, everything started to become clear.

The very first thing we need to do to work in the “Foundation style” is to build a hierarchy of nested sub-templates. Specifically, we want rows and columns in a master template and then use the standard content mechanism to drop text into the body.

Curiously, this isn’t something standard Mojolicious lets you do easily. Although in an ep (Encapsulated Perl) file, you can specify:

% layout 'template_name'

and that layout can then say:

% extends 'subtemplate_name'

the latter does not let you nest; the ‘extending’ template’s content is discarded. (Unless, that is, there has been no content yet defined: an unlikely situation.)

So let’s take the “Lite app” from Part I and add the lines shown in bold here:

#!/usr/bin/env perl
use Mojolicious::Lite;

# Documentation browser under "/perldoc"
plugin 'PODRenderer';

get '/' => sub {
 my $c = shift;
 $c->render('index',
 msg => 'Welcome to the Mojolicious real-time web framework!');
};

app->start;
__DATA__

@@ index.html.ep
% layout 'site_design';
% title 'Welcome';
<div class="row">
 <h2><%= $msg %></h2>
 <div class="small-2 columns">2 columns</div>
 <div class="small-10 columns">10 columns</div>
</div>
<div class="row">
 <div class="small-3 columns">3 columns</div>
 <div class="small-9 columns">9 columns</div>
</div>

@@ layouts/site_design.html.ep
% extends 'layouts/zurb';

This text does not appear.

@@ layouts/zurb.html.ep
<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="utf-8">
 <!-- Zurb Foundation stuff -->
 <meta name="viewport" content=
 "width=device-width, initial-scale=1.0">
 <link rel="stylesheet" href="css/normalize.css">
 <link rel="stylesheet" href="css/foundation.min.css">
 <script src="js/vendor/modernizr.js"></script>
 <!-- end Zurb -->
 <title><%= title %></title>
 </head>
 <body>
 <script src="js/vendor/jquery.js"></script>
 <script src="js/foundation.min.js"></script>
 <script>
 $(document).foundation();
 </script>
<%= content %>
 </body>
</html>

Now the index HTML calls for the site_design template, which in turn extends our Zurb Foundation template.  However, the “content” text in site_design is discarded! In order to nest templates, we must overcome this.

As of Mojolicions 6.0,  the built-in content helper functions are:

content
stash
content_for

The first lets us define the content stash (but, if that contains anything at all, the function has no effect); the second function returns the value of any stash including content; and content_for appends to the content stash. As you can see, there is no built-in way to wrap the content, or prepend to it.

LATE NOTE (3 March 2015): A pending patch will add an appropriate helper to core. The remainder of this article has been updated to reflect the newly named function. When the content_with function becomes core, the function or plugin shown below will no longer be required. − [WL]

We will have to add our own function, which means a little understanding of what is really going on. According to “Rendering” in the Mojolicious Guides,

The renderer is a tiny black box turning stash data into actual responses utilizing multiple template systems and data encoding modules.

Well that’s all wonderful, but what does the black box do exactly? In Mojolicious/Renderer.pm in your Perl installation, you can see the loop in the render function, just below the comment:

sub render

# Extends

The extends loop there descends through the template definition, which has the effect of rendering each of the include, extends, and layout calls. Again, do realize that in your template,

% layout 'site_design';

is a simple Perl function call, not some kind of magic. Understand too that the layout’s processing is deferred until after the remainder of the containing template.

To write our helper function that will wrap rather than replace the content, let’s exampien how content and content_for are defined, in Plugins/DefaultHelpers.pm:

sub _content {
my ($c, $name, $content) = @_;
$name ||= 'content';

# Set (first come)
my $hash = $c->stash->{'mojo.content'} ||= {};
$hash->{$name} //= ref $content eq 'CODE' ? $content->() : $content
if defined $content;

# Get
return Mojo::ByteStream->new($hash->{$name} // '');
}

sub _content_for {
my ($c, $name, $content) = @_;
return _content($c, $name) unless defined $content;
my $hash = $c->stash->{'mojo.content'} ||= {};
return $hash->{$name} .= ref $content eq 'CODE' ? $content->() : $content;
}

Aha! So what we want is this, just before we start our program:

app->helper(content_with => sub {
  my ($c, $name, $content) = @_;
  return unless defined $content;
  my $hash = $c->stash->{'mojo.content'} ||= {};
  return $hash->{$name} = 
    ref $content eq 'CODE' ? $content->() : $content;
});

Finally, we can write our index.html and simply declare what we want in each of the containers: header, footer, sidebar, and then the content, leaving the details of the rows and columns to our nested site layout template, as follows (new parts in bold):

#!/usr/bin/env perl
use Mojolicious::Lite;

# Documentation browser under "/perldoc"
plugin 'PODRenderer';

get '/' => sub {
  my $c = shift;
  $c->render('index',
         msg => 'Welcome to the Mojolicious real-time web framework!');
};

app->helper(content_with => sub {
  my ($c, $name, $content) = @_;
  return unless defined $content;
  my $hash = $c->stash->{'mojo.content'} ||= {};
  return $hash->{$name} = 
    ref $content eq 'CODE' ? $content->() : $content;
});

app->start;
__DATA__

@@ index.html.ep
% layout 'site_design';
% title 'Welcome';
% content header => begin
<h2><%= $msg %></h2>
% end
% content footer => begin
<h5>Copyright ⓒ <%= ((localtime())[5]+1900) %></h5>
% end
% content sidebar => begin
<ul>
  <li>Sidebar item 1</li>
  <li>Sidebar item 2</li>
</ul>
% end

This plain text is the content − the body of the page.

@@ layouts/site_design.html.ep
% extends 'layouts/zurb';

% content_with content => begin
<div class="row">
  <div class="large-12 columns"><%= content 'header' %></div>
</div>
<div class="row">
  <div class="small-3 columns"><%= content 'sidebar' %></div>
  <div class="small-9 columns"><%= content %></div>
</div>
<div class="row">
  <div class="large-12 columns"><%= content 'footer' %></div>
</div>
% end

@@ layouts/zurb.html.ep
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <!-- Zurb Foundation stuff -->
    <meta name="viewport" content=
       "width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/normalize.css">
    <link rel="stylesheet" href="css/foundation.min.css">
    <script src="js/vendor/modernizr.js"></script>
    <!-- end Zurb -->
    <title><%= title %></title>
  </head>
  <body>
    <script src="js/vendor/jquery.js"></script>
    <script src="js/foundation.min.js"></script>
    <script>
      $(document).foundation();
    </script>
<%= content %>
  </body>
</html>

Note that, prior to Mojolicions 6.0, if you use bare expressions in an .ep file, you must encase them in parentheses, as we did above:

<h5>Copyright ⓒ <%= ((localtime())[5]+1900) %></h5>

Our Wrapper As a Plugin

Now let’s make our helper a more general Plugin so we can use it in all our Mojolicious programs.

Following the Plugin documentation and referring to the Adding a Plugin to your Application section of the Cookbook, we could write this as an Application-Specific Plugin, which according to the Cookbook, “work[s] just like normal plugins and are also subclasses of Mojolicious::Plugin” should be placed in lib/MyApp/Plugin in your program directory; the example in the Cookbook would be at lib/MyApp/Plugin/MyHelpers.pm and they would start like this:

package MyApp::Plugin::MyHelpers;
use Mojo::Base 'Mojolicious::Plugin';

and would be loaded in your main program like this, for Lite:

use Mojolicious::Lite;

use lib 'lib';

plugin 'MyApp::Plugin::MyHelpers';

The Cookbook talks about application-specific plugins, and it is certainly easy to find a list of the default plugins but what if you’re writing a plugin that is used across several of your programs but is not on CPAN? Your personal or corporate repository, as it were.

Plugins are loaded by the Plugin Manager, which will find .pm files by their fully qualified names as long as they are available in @INC, whose first entry is by default:

/home/your/program_path/script/../lib

The plugin manager will also find short names if their stem is in $app->plugins->namespaces, which by default contains only:

Mojolicious::Plugin

OK so let’s code our wrapper as a basic plugin whose source code resides in lib/ContentWrapper.pm like this:

package ContentWrapper;
use Mojo::Base 'Mojolicious::Plugin';

sub register {
  my ($self, $app) = @_;

  $app->helper(content_with => sub {
            my ($c, $name, $content) = @_;
            return unless defined $content;
            my $hash = $c->stash->{'mojo.content'} ||= {};
            return $hash->{$name} = 
              ref $content eq 'CODE' ? $content->() : $content;
          }
      );
}

1;

Our main program then will start as:

sub startup {
  my $self = shift;

  # My own plugin which defines a helper
  $self->plugin('ContentWrapper');
…

See how the ContentWrapper class, and the plugin of the same name, were simply loaded from lib/ContentWrapper.pm?  It is no more complex than that.

However in general we will want to organize our files a bit better. So let’s move that into a Plugins directory.  Then we can add our namespace (and directory) to the Mojo application’s list of plugin namespaces.  Move the file to lib/Plugins/ContentWrapper.pm and change the package namespace:

package Plugins::ContentWrapper;
use Mojo::Base 'Mojolicious::Plugin';

sub register {
  my ($self, $app) = @_;

  $app->helper(content_with => sub {
            my ($c, $name, $content) = @_;
            return unless defined $content;
            my $hash = $c->stash->{'mojo.content'} ||= {};
            return $hash->{$name} = 
              ref $content eq 'CODE' ? $content->() : $content;
          }
      );
}

1;

And correlate in your main program:

sub startup {
  my $self = shift;

  push @{$self->plugins->namespaces}, 'Plugins';

  # My own plugin which defines a helper
  $self->plugin('ContentWrapper');
…

We can omit the Plugins:: specification from the call to plugin(), but the package name must exactly correspond to the location of the .pm file.

Thanks to everyone on #mojo IRC, particularly jberger.

Next time, we will start adding database functionality. Meantime, have fun with easy Foundation enabled Mojo sites!

Command Line Tools for System Monitoring

From TecMint this guide on 20 useful administration tools. You have probably seen some of them, but there are a few gems I hadn’t run across in all my years of Linux:

  • vmstat
  • lsof
  • top
  • htop
  • tcpdump
  • iptraf − IP traffic monitor: Surprisingly useful!
  • iftop
  • nethogs
  • netstat
  • iotop − what’s eating your disk?
  • iostat
  • psacct
  • monit
  • arpwatch
  • nmon

Perl 5.21 cpanm fails to install DBIx::Connector

As you may find if you use a very recent environment with perlbrew, The latest Perls do not contain CGI.pm, so when you attempt to use cpanm (CPAN minus) to install a module like DBIx::Connector,  it will fail and you will see in the created log file a line that contains:

Can't locate CGI.pm in @INC (you may need to install the CGI module)

This turns out to be, if you trace it,  because the test module Test::MockModule still has a CGI based test.  You can make the desired module install by forcing the Test component to install anyway:

$ cpanm Test::MockModule --force
(succeeds)
$ cpanm DBIx::Connector
(succeeds)

That’s really all there is to it.

"Si datur citrea, sucus faciunt" (When life gives you lemons, make lemonade)