App-Diskd

 view release on metacpan or  search on metacpan

lib/App/Diskd.pm  view on Meta::CPAN

straightforward process. Based on this experience, I would definitely
recommend other Perl programmers to consider POE for programs of this
sort (network daemons) as well as for any other task where the an
event-based approach is suitable.


=head1 POINTS OF INTEREST

From the outset, I had decided that I would modularise the code and
use different objects (classes) for each functional part of the
overall program. Besides being a reasonable approach in general, it
also turned out that this was a good practical fit with the POE way of
doing things since I could use a separate POE session for each
class. Using separate classes meant that, for example, I could have
the same event name across several different sessions/classes without
needing to worry about whether they would interfere with each
other. This was a boon considering that most of my POE code started as
cut and paste from other examples.

For the remainder of this section, I would like to simply go through
each of the classes used in the program and give some brief notes. I
have attempted to comment the code to make it easier to read and
understand, but the notes here give some extra context and extra
levels of detail.

=head2 Info class

This class simply encapsulates the data structures that are collected
locally and shared among nodes. A distinction is made between the two
so that calling classes have a convenient interface for updating only
local data (eg, DiskWatcher), or querying globally-shared data (eg, a
client running a 'list' command).

The Info class does not have an associated POE session, though a
reference to the Info object is passed to every class/POE session that
needs to access/update it. So even though it doesn't use POE itself,
it is basically the glue that holds all the POE sessions together and
gives them meaning.

The current implementation simply keeps all the data in memory, though
it would be simple enough to either:

=over

=item * provide a routine to be called at program startup to read in saved data from a file or other backing storage (along with a complementary routine to save the data when the program is shutting down); or

=item * interface with a database to act as a permanent storage medium (POE provides mechanisms for doing this asynchronously, which might be appropriate here)

=back

Internally, this class also uses YAML to pack and unpack (serialise
and deserialise) the stored data. This is used by the MulticastServer
class to safely transmit and receive data within the UDP packets. It
could also be used to load/save the data to local storage between
program runs (ie, provide persistence of data).


=head2 DiskWatcher class

This class sets up a POE session that periodically calls the external
'blkid' program. It uses POE::Wheel::Run to do this in the background
so that the parent program does not block while waiting on the child
program to run to completion.

In some cases, blkid can hang (such as if a device has disappeared
without being cleanly unmounted or disconnected) or fail altogether
(such as the user not having sufficient rights, or the program not
being present on the system). This class handles both cases
gracefully.

=head2 MountWatcher class

This is not implemented, but the idea is that in addition to peers
announcing and tracking which disks are attached to which machines,
they would also share information about which of those disks are
currently mounted.

A simple implementation would simply call the system 'mount' command
in a similar way that 'blkid' is called in the DiskWatcher class.

If implemented, it might also make sense (subject to security
considerations) to allow clients to issue commands to mount (and
possibly unmount) selected disks. This would make it easier for other
applications to search for a disk and, if it is found, issue the
command for the machine to which the disk is attached to mount it
before the remote host tries to mount it (with something like nfs or
sshfs, for example). The point here would be to provide a relatively
location-independent way of doing remote mounts.

=head2 MulticastServer class

This class is responsible for sending and receiving packets to and
from a specific multicast channel. It begins by joining the multicast
channel and then sets up:

=over

=item * a listener which receives updates from other peers; and

=item * a periodic event that sends information about locally-attached disks to all peers

=back

All packets are sent using UDP, so there is no acknowledgement
process. Because packets are sent using multicast, a single packet
should find its way to all members of the multicast group.

A "ttl" ("time to live") option is provided so that if peers are on
different subnets, a multicast-aware router can forward the packets to
any subnet that has a subscribed peer. I have tested this and
confirmed that it works, at least for peers separated by a single
router hop. Simply set the value to (maximum number of hops + 1).

The MulticastServer object relies on the Info object to provide
(de-)serialisation of the data. The way this is currently implemented
(using YAML and some extra checking on the received data structure),
this prevents the possibility of a rogue peer joining the network and
sending data packets that are specially crafted so as to allow them to
execute arbitrary Perl code (ie, receiving arbitrary data should not
present a security risk). The question of whether I<broadcasting>
(multicasting) information about what disks are attached represents a



( run in 1.798 second using v1.01-cache-2.11-cpan-d8267643d1d )