Moo and Type::Tiny

December 14, 2014

At the start of 2014 I was working on a project to further improve the LCFG client. When I hit problems with Moose and its memory usage I discovered the excellent Moo framework which provides all the nice bits but is much less heavyweight. As part of the Perl Advent Calendar for 2014 someone has written a great introductory article on using Moo along with Type::Tiny. I’ve learnt a few things, I particularly like the idea of a “type library” as a good way to organize all the local types.


LCFG::Build::Skeleton changes

December 8, 2014

At the LCFG Annual Review meeting held last week one topic which was discussed was the idea of all Perl based LCFG components being implemented as modules with the component script just being a very thin wrapper which loads the module and calls the dispatch method. This has been our recommended coding style for quite a while now and we use this approach for many of the core components.

During the discussion I realised that the lcfg-skeleton tool which is used to create the outline directory structure for new projects does not support this way of working. To make it really easy to create new Perl-based components which follow recommended best-practice I have consequently updated LCFG-Build-Skeleton. The new version 0.4.1 creates a module file (e.g. lib/LCFG/Component/Foo.pm), the necessary CMake file and also tweaks the specfile appropriately. This will be in the stable release on Thursday 18th December or you can grab it from CPAN now.


LCFG authorization

December 3, 2014

The authorization of LCFG component methods (which are called using the om command) is typically done using the LCFG::Authorize module. This is limited to checking usernames and membership of groups managed in LCFG.

In Informatics we have for a long-time used a different module – DICE::Authorize – which extends this to also checking membership of a netgroup. Recently we discovered some problems with our implementation of this functionality which make it very inflexible. We have been connecting directly to the LDAP server and doing the lookup based on hardcoded information in the module. As this really just boils down to checking membership of a netgroup this can clearly be done more simply by calling the innetgr function. This will work via the standard NS framework so will handle LDAP, NIS or whatever is required. The necessary details are then only stored in the standard location and not embedded into the code.

Rather than just rewrite the DICE::Authorize module I took the chance to move the functionality to the LCFG layer, so we now have LCFG::Authorize::NetGroups. This nicely sub-classes the standard module so that if the user is not a member of a netgroup the other checks are then carried out. This is much better code reuse, previously we had two distinct implementations of the basic checks.

Having a new implementation of the authorization module is also handy for dealing with the transition stage. We can keep the old one around so that if a problem is discovered with the new code we can quickly switch back to the old code.

I also took the chance to improve the documentation of the authorization framework so if you’re still running om as root now is a good time to improve things!


Sub-classing LCFG components

December 3, 2014

One topic that often comes up in discussions about how to make things easier for LCFG component authors is the idea of sub-classing.

Although I had never tried it I had always assumed this was possible. Recently whilst looking through the LCFG::Component code I noticed that the list of methods are looked up in the symbol table for the module:

    my $mtable = {};
    for my $method ( ( keys %LCFG::Component:: ),
        ( eval 'keys %' . ref($self) . q{::} ) )
    {
        if ( $method =~ m/^method_(.*)/i ) {
            $mtable->{ lc $1 } = $method;
        }
    }
    $self->{_METHOD} = lc $_METHOD;
    my $_FUNCTION = $mtable->{ $self->{_METHOD} };

So, this will work if your method comes from LCFG::Component or LCFG::Component::Foo but it wouldn’t work if you have a sub-class of Foo. You would potentially miss out on methods which are only in Foo (or have to copy/paste them into your sub-class).

Not only does this make sub-classing tricky it also involves a horrid string eval. There had to be a better way. Thankfully I was already aware of the Class::Inspector module which can do the necessary. This module is widely used by projects such as DBIx::Class and Catalyst so is likely to be reliable. It has a handy methods method which does what we need:

    my $_FUNCTION;
    my $public_methods = Class::Inspector->methods( ref($self), 'public' );
    for my $method (@{$public_methods}) {
        if ( $method =~ m/^Method_(\Q$_METHOD\E)$/i ) {
            $_FUNCTION = $method;
            $_METHOD = $1;
            last;
        }
    }

Much nicer code and a tad more efficient. Now the LCFG component Perl modules are properly sub-classable.