NAME

IPDB - Perl interface to Cambridge IP address register database

SYNOPSIS

 use Moo;

 with qw(
  ipreg::IPDB
  ...
 );

 # database connection management by ipreg::v3::Jackdaw
 $ipdbh->dbconnect == 0 or die $ipdbh->dberr;

 die "Database unavailable" unless $ipdbh->available;
 print $ipdbh->motd;
 $ipdbh->motd("New message");

 $ipdbh->create_ip_object( 'object_type', attr=>'value', ... )
                         || die $ipdbh->errstr;
 $ipdbh->modify_ip_object( 'object_type', {selector=>'value',... },
                           attr=>'value', ... )
                         || die $ipdbh->errstr;
 $ipdbh->destroy_ip_object( 'object_type', {selector=>'value',... } )
                          || die $ipdbh->errstr;
 $attribute_hashref = $ipdbh->query_ip_object( 'object_type',
                                        {selector=>'value',... } )
                                      || die "No such object";

 @required_attributes =
    $ipdbh->ip_object_required_attributes( 'object_type' );
 @optional_attributes =
    $ipdbh->ip_object_optional_attributes( 'object_type' );
 @primary_key =
    $ipdbh->ip_object_primary_key( 'object_type' );
 $attribute_format_hash =
    $ipdbh->ip_object_field_format( 'object_type', 'attribute_name' );
 $attribute_order_arrayref =
    $ipdbh->ip_object_field_order( 'object_type' );
 @object_types =
    $ipdbh->ip_object_types();

 $ipdbh->commit;
 $ipdbh->rollback;

 $dbh = $ipdbh->dbh;

 $ipdbh->v4_simple_register (attribute=>'value',...)
                            || die $ipdbh->errstr;
 $ipdbh->v4_simple_modify ('<name_or_address>',attribute=>'value',...)
                          || die $ipdbh->errstr;
 $ipdbh->v4_simple_rename ($oldname,$newname)
                          || die $ipdbh->errstr;
 $ipdbh->v4_simple_rescind ('<name_or_address>')
                           || die $ipdbh->errstr;
 print $ipdbh->text_info ('<name_or_address>');

 $dquad = ipreg::IPDB->hex8_to_dquad( $hex8 );
 $hex8 = ipreg::IPDB->dquad_to_hex8( $dquad );
   die "Malformed dquad $dquad" unless defined $hex8;
 $hex8 = ipreg::IPDB->int_to_hex8( $int );
 $int = ipreg::IPDB->hex8_to_int( $hex8 );
 $dquad = ipreg::IPDB->int_to_dquad( $int );
 $int = ipreg::IPDB->dquad_to_int( $dquad );
   die "Malformed dquad $dquad" unless defined $int;
 $hostmask = ipreg::IPDB->width_to_hostmask( $width );
 $netmask = ipreg::IPDB->width_to_netmask( $width );

 $colonsep = ipreg::IPDB->hex32_to_colonsep( $hex32 ); # See rfc4291
 $hex32 = ipreg::IPDB->colonsep_to_hex32( $colonsep );
 $colonsep = ipreg::IPDB->hex16_to_colonsep( $hex16 );
 $hex16 = ipreg::IPDB->colonsep_to_hex16( $colonsep );

 $text = IPDB->hex_to_text( $hex_8_or_32 );
 $hex = IPDB->text_to_hex( $dquad_or_colonsep );

DESCRIPTION

IPDB is a perl interface to the Oracle database supporting the IP address register at Cambridge University.

This version of the library has been adapted for use as a Moo::Role on the ipreg:v3 web user interface.

Nothing in IPDB is any part of the implementation of security policy. This package is in no way privileged beyond its caller, and is not the only route into the database. Any checks herein are for the benefit of the caller only. Security and integrity are implemented in the underlying database engine. If you want to write raw SQL you can (but beware of changes in the unspecified parts of the underlying database).

Class public utility methods

Many of these are concerned with interconversion of data types. You need to know that IPv4 addresses are represented in SQL as raw 4-byte values, usually converted via DBI to strings of 8 hex characters, referred to as hex8. For example '836F0102' is the SQL representation of '131.111.1.2'. The latter format, known as dquad, is normally presented to users and used in most Perl code. Occasionally it is convenient, especially for performing masking operations, to represent an address as a plain integer, known as int format. IPv6 addresses are represented in SQL as raw 16-byte values (made up of 8-byte prefix and interface-id parts), usually converted via DBI to strings of 32 hex characters, referred to as hex32, and there is also a textual representation defined in rfc4291 and referred to here as colonsep. See the SYNOPSIS section for the list of available conversion methods.

Error reporting

All ipdbh methods return something that tests TRUE if they succeed, or throw an exception if they fail.

Connections, etc.

Before any substantive interaction with the database, a connection, session or whatever you want to call it, must be established. This is done by some other role associated with the handle object, typically ipreg::v3::Jackdaw.

  my $current_prefix = $ipdbh->prefix();
  my $old_prefix = $ipdbh->prefix($new_prefix);

The "prefix" attribute defaults to "MY_", and is used by the database access methods as a prefix to table names. Thus by default the views MY_BOX and MY_V4_ADDRESS will be accessed rather than the tables BOX and V4_ADDRESS. The bare tables can be referenced by setting "prefix" to the empty string. (But the bare tables are not accessible unless you are authenticated to the database as the "ipreg" user.)

You might also be curious about the related "db_owner" attribute, which defaults to "IPREG" and (if not null) is prefixed to table, view and package names, with a dot, in front of the "prefix". Thus for example in default IPDB references the view IPREG.MY_BOX, and the stored procedure IPREG.HEX8_TO_DQUAD. This attribute is intended solely to assist testing in sand-box databases.

To assist in the construction of external SQL, the combined prefix is available (read-only) as

  my $full_prefix = $ipdbh->full_prefix();

Database availability and message of the day

The database isn't always available to users, even though the underlying database may be running. This is normally indicative of maintenance in progress. The availability can be checked, thus avoiding a bloody nose, with

 if ( $ipdbh->available ) ...

This should be checked overtly immediately prior to any database operation. connect and plumb do not check this this automatically, partly since db_owner is not known at that stage, and partly because the state may change subsequently while the connection is still open.

There is also a message of the day, possibly null. The only allowed action on this is to display it for human eyes, for example

 print $ipdbh->motd;

There may be a message of the day even when the database is unavailable, and it is not an error to call motd when the database is unavailable. At worst it yields the empty string. This is an exception to the general error flagging rule.

If called with an argument, motd sets the motd, given sufficient privilege, and yields the usual error indication result. The transaction is committed.

The sysinfo method gets the available, areader, and registrar flags and the motd from the database and caches the results. If you are doing something longwinded, pass an extra argument so that the cache is refreshed.

  my $sysinfo = $ipdbh->sysinfo;
  if ( $sysinfo->{available} ) ...

Operating on IP database objects

Although you can (and may well have to) wade in with your own SQL applied through the DBI methods, some perl-ish utility methods are provided to make this more palatable for ordinary requirements and to reduce the scope for mistakes. These are essentially just convenience interfaces to the INSERT, UPDATE and DELETE SQL operations for the known tables.

You do need to understand the underlying tables to use these routines. See the v4_simple methods if you don't want or need to understand that quite considerable complexity.

These routines rollback on error, but do not commit, so that you can use them to build up multiphase atomic operations.

create_ip_object

        This creates a single basic object in the database. That is, it
        inserts a row into a table. There is some checking for syntactic
semantic sanity. Example

  $ipdbh->create_ip_object(
            'box', # The object type
            hostname => 'host.dom.ain',
             ... )

modify_ip_object

Example

  $dbh->modify_ip_object (
            'box', # object type
            { name => 'host.dom.ain' }, # Identify box to be modified
            owner => 'Fred Bloggs'   # New attribute value
            ... )

The key=>value pairs (often just the one) must specify the primary key.

destroy_ip_object

Example

  $dbh->destroy_ip_object (
            'box', # object type
            { name => 'host.dom.ain' } ) # Identify box to be destroyed

The key=>value pairs (often just the one) must specify the primary key.

query_ip_object

The data values currently associated with these objects can be retrieved with

    $hash_ref = $ipdbh->query_ip_object( $object_type, {key=>'value',...} );

Note that the returned hash includes some automatically maintained data items that are not listed by ip_object_required_attributes or ip_object_optional_attributes (see below), notably 'update_date' and 'updated_by'.

The key=>value pairs (often just the one) must specify the primary key.

IP object types and attributes

The available object types, i.e. SQL tables, for the ???_ip_object methods can be obtained as

    my @types = $ipdbh->ip_object_types;

and the valid attributes, i.e. SQL table columns, can be retrieved as

    my @required_attributes =
            $ipdbh->ip_object_required_attributes( $object_type );
    my @optional_attributes =
            $ipdbh->ip_object_optional_attributes( $object_type );

The primary key (which can of course be composite) can be obtained as

    my @pkey =
       $ipdbh->ip_object_primary_key( $object_type );  # NB an array

Note that all of the above are actually the SQL column and table names.

Some apparatus is provided to assist with automatic formatting of object attributes for input or output. For each and every attribute a format can be obtained -

  $format_hashref
       = $ipdbh->ip_object_field_format( $object_type, $field_name );

The hash includes elements 'display_width', 'externalise' and 'internalise'. 'display_width' is not a maximum but rather a recommendation for the width of a scrollable field. 'externalise' and 'internalise' are references to procedures that convert between human-comprehensible form and database form. Usually these are the same and the procedures are just 'sub{$_}', but a notable case they do help with is IP address, which the database holds as (raw but shows as) hex string.

For some object types only, currently just v4_address, there is also an element 'sql_externalise'. You should test whether such an element exists in any particular case. If it does then it holds a reference to a method that yields the name of an sql procedure to externalise data. This feature is really only of use when you don't know what you are doing.

  if (my $procref = $format_hashref->{sql_externalise}) {
      my $procname = &$procref($ipdbh);
      $sql_fragment = "WHERE $procname($fieldname) LIKE '131.111.%'";
  }else{ ... }

A recommended order in which to display the fields is available -

  $field_names_arrayref
      = $ipdbh->ip_object_field_order( $object_type );

The read-only fields are included.

Easy-to-use methods

Several methods are provided to perform the most commonly required operations (some of which involve multiple database operations). They make no attempt to cope with the general or awkward cases, but go to some length to make the common operations relatively painless.

These easy-to-use methods always either commit or rollback.

text_info

This ferrets out most of what you might want to discover about an address or name, returning the result as text. In common with other text-returning methods, the result contains newlines and ends with one.

Examples -

    print $dbh->text_info( 'my.dom.ain');
    print $dbh->text_info( '1.2.3.4' );

v4_simple_register

Does what is required for issuing an IP address for a new box with a single network interface. You can specify the particular address to use, or merely specify a management zone, or specify a subnet, or specify and address range, or leave the choice completely open to anything accessible to you. Returns a string containing a representation of the resulting assignment, if successful, or FALSE if not.

Example

    print $ipdbh->v4_simple_register(
                     mzone => 'cs',
                     name => 'host.dom.ain',
                     equipment => 'ratcage',
                     location => 'rm 101',
                     owner => 'Minitrue',
                     sysadmin => 'CO',
                      ... )
           || die $ipdbh->errstr;

v4_simple_text

You may want to re-generate the text that was (or would have been) returned with a successful v4_simple_register, and this can be done by

  $text =  $ipdbh->v4_simple_text( '1.2.3.4' )  # or  ( 'host.dom.ain' )

Note that this is a more compact layout than text_info yields, and applicable only to simple cases.

v4_simple_modify

Example -

    $ipdbh->v4_simple_modify( '1.2.3.4',  # or 'host.dom.ain'
                              equipment => 'thumbscrew' )
          || die $ipdbh->errstr;

v4_simple_rename

Example

    print $ipdbh->v4_simple_rename( 'old.dom.ain', 'new.dom.ain' )
          || die $ipdbh->errstr;

v4_simple_rescind

Example -

    print $ipdbh->v4_simple_rescind( 'host.dom.ain')
          || die $ipdbh->errstr;

v4_simple_info

If the target of this query is a simple v4 object, in the sense understood by v4_simple_register, this will return (as a reference to a hash) the fields that you (might have) used to create it that way. Example -

    my $info = $ipdbh->v4_simple_info( "host.dom.ain" );
    print $info->{"location"}; ....

Some helper methods

These methods provide useful subroutines for the more complicated operations.