diff options
| -rw-r--r-- | perl/Wallet/ACL.pm | 10 | ||||
| -rw-r--r-- | perl/Wallet/Object/Base.pm | 11 | ||||
| -rw-r--r-- | perl/Wallet/Object/Keytab.pm | 4 | ||||
| -rw-r--r-- | perl/Wallet/Schema.pm | 72 | ||||
| -rw-r--r-- | perl/Wallet/Server.pm | 21 | ||||
| -rwxr-xr-x | perl/t/init.t | 19 | ||||
| -rwxr-xr-x | perl/t/keytab.t | 4 | ||||
| -rwxr-xr-x | perl/t/object.t | 4 | ||||
| -rwxr-xr-x | perl/t/schema.t | 17 | ||||
| -rwxr-xr-x | perl/t/server.t | 8 | 
10 files changed, 144 insertions, 26 deletions
| diff --git a/perl/Wallet/ACL.pm b/perl/Wallet/ACL.pm index 6a07366..f04217e 100644 --- a/perl/Wallet/ACL.pm +++ b/perl/Wallet/ACL.pm @@ -50,8 +50,12 @@ sub new {      } else {          $sql = 'select ac_id, ac_name from acls where ac_name = ?';      } -    ($data, $name) = eval { $dbh->selectrow_array ($sql, undef, $id) }; +    eval { +        ($data, $name) = $dbh->selectrow_array ($sql, undef, $id); +        $dbh->commit; +    };      if ($@) { +        $dbh->rollback;          die "cannot search for ACL $id: $@\n";      } elsif (not defined $data) {          die "ACL $id not found\n"; @@ -271,9 +275,11 @@ sub list {          while (defined ($entry = $sth->fetchrow_arrayref)) {              push (@entries, [ @$entry ]);          } +        $self->{dbh}->commit;      };      if ($@) {          $self->error ("cannot retrieve ACL $self->{id}: $@"); +        $self->{dbh}->rollback;          return;      } else {          return @entries; @@ -320,9 +326,11 @@ sub history {              }              $output .= "\n    by $data[3] from $data[4]\n";          } +        $self->{dbh}->commit;      };      if ($@) {          $self->error ("cannot read history for $self->{id}: $@"); +        $self->{dbh}->rollback;          return undef;      }      return $output; diff --git a/perl/Wallet/Object/Base.pm b/perl/Wallet/Object/Base.pm index ada211c..1371f7f 100644 --- a/perl/Wallet/Object/Base.pm +++ b/perl/Wallet/Object/Base.pm @@ -41,6 +41,7 @@ sub new {      $dbh->{PrintError} = 0;      my $sql = 'select ob_name from objects where ob_type = ? and ob_name = ?';      my $data = $dbh->selectrow_array ($sql, undef, $type, $name); +    $dbh->commit;      die "cannot find ${type}:${name}\n" unless ($data and $data eq $name);      my $self = {          dbh  => $dbh, @@ -240,9 +241,11 @@ sub _get_internal {          my $sql = "select $attr from objects where ob_type = ? and              ob_name = ?";          $value = $self->{dbh}->selectrow_array ($sql, undef, $type, $name); +        $self->{dbh}->commit;      };      if ($@) {          $self->error ($@); +        $self->{dbh}->rollback;          return;      }      return $value; @@ -345,9 +348,11 @@ sub flag_check {          my $sql = 'select fl_flag from flags where fl_type = ? and fl_name = ?              and fl_flag = ?';          $value = $dbh->selectrow_array ($sql, undef, $type, $name, $flag); +        $dbh->commit;      };      if ($@) {          $self->error ("cannot check flag $flag for ${type}:${name}: $@"); +        $dbh->rollback;          return;      } elsif ($value) {          return 1; @@ -401,10 +406,12 @@ sub flag_list {          while (defined ($flag = $sth->fetchrow_array)) {              push (@flags, $flag);          } +        $self->{dbh}->commit;      };      if ($@) {          my $id = $self->{type} . ':' . $self->{name};          $self->error ("cannot retrieve flags for $id: $@"); +        $self->{dbh}->rollback;          return;      } else {          return @flags; @@ -490,10 +497,12 @@ sub history {              }              $output .= "\n    by $data[5] from $data[6]\n";          } +        $self->{dbh}->commit;      };      if ($@) {          my $id = $self->{type} . ':' . $self->{name};          $self->error ("cannot read history for $id: $@"); +        $self->{dbh}->rollback;          return undef;      }      return $output; @@ -550,9 +559,11 @@ sub show {          my $sql = "select $fields from objects where ob_type = ? and              ob_name = ?";          @data = $self->{dbh}->selectrow_array ($sql, undef, $type, $name); +        $self->{dbh}->commit;      };      if ($@) {          $self->error ("cannot retrieve data for ${type}:${name}: $@"); +        $self->{dbh}->rollback;          return undef;      }      my $output = ''; diff --git a/perl/Wallet/Object/Keytab.pm b/perl/Wallet/Object/Keytab.pm index f91abff..025c9e1 100644 --- a/perl/Wallet/Object/Keytab.pm +++ b/perl/Wallet/Object/Keytab.pm @@ -467,9 +467,11 @@ sub enctypes_list {          while (defined ($entry = $sth->fetchrow_arrayref)) {              push (@enctypes, @$entry);          } +        $self->{dbh}->commit;      };      if ($@) {          $self->error ($@); +        $self->{dbh}->rollback;          return;      }      return @enctypes; @@ -562,9 +564,11 @@ sub attr {                  while (defined ($target = $sth->fetchrow_array)) {                      push (@targets, $target);                  } +                $self->{dbh}->commit;              };              if ($@) {                  $self->error ($@); +                $self->{dbh}->rollback;                  return;              }              return @targets; diff --git a/perl/Wallet/Schema.pm b/perl/Wallet/Schema.pm index ec690e1..030905e 100644 --- a/perl/Wallet/Schema.pm +++ b/perl/Wallet/Schema.pm @@ -14,7 +14,7 @@ package Wallet::Schema;  require 5.006;  use strict; -use vars qw(@TABLES $VERSION); +use vars qw(@SQL @TABLES $VERSION);  use DBI; @@ -28,28 +28,31 @@ $VERSION = '0.02';  ##############################################################################  # Create a new Wallet::Schema object, parse the SQL out of the documentation, -# and store it in the object. +# and store it in the object.  We have to store the SQL in a static variable, +# since we can't read DATA multiple times.  sub new {      my ($class) = @_; -    local $_; -    my ($found, @sql); -    my $command = ''; -    while (<DATA>) { -        if (not $found and /^=head1 SCHEMA/) { -            $found = 1; -        } elsif ($found and /^=head1 /) { -            last; -        } elsif ($found and /^  /) { -            s/^  //; -            $command .= $_; -            if (/;$/) { -                push (@sql, $command); -                $command = ''; +    unless (@SQL) { +        local $_; +        my $found; +        my $command = ''; +        while (<DATA>) { +            if (not $found and /^=head1 SCHEMA/) { +                $found = 1; +            } elsif ($found and /^=head1 /) { +                last; +            } elsif ($found and /^  /) { +                s/^  //; +                $command .= $_; +                if (/;$/) { +                    push (@SQL, $command); +                    $command = ''; +                }              }          } +        close DATA;      } -    close DATA; -    my $self = { sql => [ @sql ] }; +    my $self = { sql => [ @SQL ] };      bless ($self, $class);      return $self;  } @@ -84,6 +87,31 @@ sub create {      }  } +# Given a database handle, try to remove the wallet database tables by +# reversing the SQL.  Do this in a transaction regardless of the database +# settings and throw an exception if this fails. +sub drop { +    my ($self, $dbh) = @_; +    my @drop = map { +        if (/^\s*create\s+table\s+(\S+)/i) { +            "drop table if exists $1;"; +        } else { +            (); +        } +    } reverse @{ $self->{sql} }; +    eval { +        $dbh->begin_work if $dbh->{AutoCommit}; +        for my $sql (@drop) { +            $dbh->do ($sql, { RaiseError => 1, PrintError => 0 }); +        } +        $dbh->commit; +    }; +    if ($@) { +        $dbh->rollback; +        die "$@\n"; +    } +} +  ##############################################################################  # Schema  ############################################################################## @@ -134,6 +162,14 @@ drop any existing tables and will therefore fail if a wallet database has  already been created.  On any error, this method will throw a database  exception. +=item drop(DBH) + +Given a connected database handle, drop all of the wallet tables from that +database if any of those tables exist.  This method will only remove tables +that are part of the current schema or one of the previous known schema and +won't remove other tables.  On any error, this method will throw a database +exception. +  =item sql()  Returns the schema and the population of the normalization tables as a list diff --git a/perl/Wallet/Server.pm b/perl/Wallet/Server.pm index 429b3fb..04e8fd9 100644 --- a/perl/Wallet/Server.pm +++ b/perl/Wallet/Server.pm @@ -85,6 +85,18 @@ sub initialize {      return $class->new ($user, 'localhost');  } +# The same as initialize, but also drops any existing tables first before +# creating the schema.  Takes the same arguments and throws an exception on +# failure. +sub reinitialize { +    my ($class, $user) = @_; +    my $dbh = $class->_open_db; +    my $schema = Wallet::Schema->new; +    $schema->drop ($dbh); +    $dbh->disconnect; +    return $class->initialize ($user); +} +  # Create a new wallet server object.  A new server should be created for each  # user who is making changes to the wallet.  Takes the principal and host who  # are sending wallet requests.  Opens a connection to the database that will @@ -752,6 +764,15 @@ privileged operations.  On any error, this method throws an exception. +=item reinitialize(PRINCIPAL) + +Performs the same actions as initialize(), but first drops any existing +wallet database tables from the database, allowing this function to be +called on a prior wallet database.  All data stored in the database will be +deleted and a fresh set of wallet database tables will be created. + +On any error, this method throws an exception. +  =back  =head1 INSTANCE METHODS diff --git a/perl/t/init.t b/perl/t/init.t index 3fa026f..81c034d 100755 --- a/perl/t/init.t +++ b/perl/t/init.t @@ -8,7 +8,7 @@  #  # See LICENSE for licensing terms. -use Test::More tests => 8; +use Test::More tests => 16;  use Wallet::ACL;  use Wallet::Config; @@ -34,5 +34,22 @@ isnt ($entries[0], undef, ' which is a valid entry');  is ($entries[0][0], 'krb5', ' of krb5 scheme');  is ($entries[0][1], 'admin@EXAMPLE.COM', ' with the right user'); +# Test reinitialization. +$server = eval { Wallet::Server->reinitialize ('admin@EXAMPLE.COM') }; +is ($@, '', 'Reinitialization did not die'); +ok ($server->isa ('Wallet::Server'), ' and returned the right class'); + +# Now repeat the database content checks. +$acl = eval { Wallet::ACL->new ('ADMIN', $server->dbh) }; +is ($@, '', 'Retrieving ADMIN ACL successful'); +ok ($acl->isa ('Wallet::ACL'), ' and is the right class'); +@entries = $acl->list; +is (scalar (@entries), 1, ' and has only one entry'); +isnt ($entries[0], undef, ' which is a valid entry'); +is ($entries[0][0], 'krb5', ' of krb5 scheme'); +is ($entries[0][1], 'admin@EXAMPLE.COM', ' with the right user'); +  # Clean up. +my $schema = Wallet::Schema->new; +$schema->drop ($server->dbh);  unlink 'wallet-db'; diff --git a/perl/t/keytab.t b/perl/t/keytab.t index d7c2a02..f08bd31 100755 --- a/perl/t/keytab.t +++ b/perl/t/keytab.t @@ -200,7 +200,7 @@ sub stop_remctld {  }  # Use Wallet::Server to set up the database. -my $server = eval { Wallet::Server->initialize ($user) }; +my $server = eval { Wallet::Server->reinitialize ($user) };  is ($@, '', 'Database initialization did not die');  ok ($server->isa ('Wallet::Server'), ' and returned the right class');  my $dbh = $server->dbh; @@ -861,4 +861,6 @@ EOO  }  # Clean up. +my $schema = Wallet::Schema->new; +$schema->drop ($dbh);  unlink ('wallet-db', 'krb5cc_temp', 'krb5cc_test', 'test-acl', 'test-pid'); diff --git a/perl/t/object.t b/perl/t/object.t index bf100ea..42700d0 100755 --- a/perl/t/object.t +++ b/perl/t/object.t @@ -28,7 +28,7 @@ my @trace = ($user, $host, time);  my $princ = 'service/test@EXAMPLE.COM';  # Use Wallet::Server to set up the database. -my $server = eval { Wallet::Server->initialize ($user) }; +my $server = eval { Wallet::Server->reinitialize ($user) };  is ($@, '', 'Database initialization did not die');  ok ($server->isa ('Wallet::Server'), ' and returned the right class');  my $dbh = $server->dbh; @@ -321,4 +321,6 @@ EOO  is ($object->history, $output, ' and the history is correct');  # Clean up. +my $schema = Wallet::Schema->new; +$schema->drop ($dbh);  unlink 'wallet-db'; diff --git a/perl/t/schema.t b/perl/t/schema.t index 01b2b88..9e2d84f 100755 --- a/perl/t/schema.t +++ b/perl/t/schema.t @@ -8,7 +8,7 @@  #  # See LICENSE for licensing terms. -use Test::More tests => 5; +use Test::More tests => 8;  use DBI;  use Wallet::Schema; @@ -31,5 +31,20 @@ $dbh->{PrintError} = 0;  eval { $schema->create ($dbh) };  is ($@, '', "create() doesn't die"); +# Test dropping the database. +eval { $schema->drop ($dbh) }; +is ($@, '', "drop() doesn't die"); +my $sql = "select name from sqlite_master where type = 'table'"; +my $sth = $dbh->prepare ($sql); +$sth->execute; +my ($table, @tables); +while (defined ($table = $sth->fetchrow_array)) { +    push (@tables, $table) unless $table =~ /^sqlite_/; +} +is ("@tables", '', ' and there are no tables in the database'); +eval { $schema->create ($dbh) }; +is ($@, '', ' and we can run create again'); +  # Clean up. +eval { $schema->drop ($dbh) };  unlink 'wallet-db'; diff --git a/perl/t/server.t b/perl/t/server.t index b0c196b..2520e62 100755 --- a/perl/t/server.t +++ b/perl/t/server.t @@ -866,6 +866,11 @@ is ($server->store ('base', 'service/foo', 'stuff'), undef,  is ($server->error, "$user2 not authorized to create base:service/foo",      ' with the right error'); +# Clean up. +my $schema = Wallet::Schema->new; +$schema->drop ($server->dbh); +unlink 'wallet-db'; +  # Now test handling of some configuration errors.  undef $Wallet::Config::DB_DRIVER;  $server = eval { Wallet::Server->new ($user2, $host) }; @@ -880,6 +885,3 @@ $Wallet::Config::DB_INFO = 't';  $server = eval { Wallet::Server->new ($user2, $host) };  like ($@, qr/^cannot connect to database: /,        ' or if the database connection fails'); - -# Clean up. -unlink 'wallet-db'; | 
