summaryrefslogtreecommitdiff
path: root/rt/sbin/rt-setup-database.in
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2012-06-07 00:56:06 -0700
committerIvan Kohler <ivan@freeside.biz>2012-06-07 00:56:06 -0700
commit43a06151e47d2c59b833cbd8c26d97865ee850b6 (patch)
tree42c51d94e7fa265461b508d061562be204ccc2c1 /rt/sbin/rt-setup-database.in
parent6587f6ba7d047ddc1686c080090afe7d53365bd4 (diff)
starting to work...
Diffstat (limited to 'rt/sbin/rt-setup-database.in')
-rw-r--r--rt/sbin/rt-setup-database.in280
1 files changed, 197 insertions, 83 deletions
diff --git a/rt/sbin/rt-setup-database.in b/rt/sbin/rt-setup-database.in
index 1257088..2efb9f3 100644
--- a/rt/sbin/rt-setup-database.in
+++ b/rt/sbin/rt-setup-database.in
@@ -3,7 +3,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -76,34 +76,57 @@ BEGIN {
}
-#This drags in RT's config.pm
-# We do it in a begin block because RT::Handle needs to know the type to do its
-# inheritance
-BEGIN {
- use RT;
- RT::LoadConfig();
- RT::InitClasses();
-}
-
use Term::ReadKey;
use Getopt::Long;
$| = 1; # unbuffer all output.
-my %args;
+my %args = (
+ dba => '@DB_DBA@',
+);
GetOptions(
\%args,
'action=s',
'force', 'debug',
'dba=s', 'dba-password=s', 'prompt-for-dba-password',
- 'datafile=s', 'datadir=s'
+ 'datafile=s', 'datadir=s', 'skip-create', 'root-password-file=s',
+ 'help|h',
);
-unless ( $args{'action'} ) {
- help();
- exit(-1);
+no warnings 'once';
+if ( $args{help} || ! $args{'action'} ) {
+ require Pod::Usage;
+ Pod::Usage::pod2usage({ verbose => 2 });
+ exit;
+}
+
+require RT;
+RT->LoadConfig();
+RT->InitClasses();
+
+# Force warnings to be output to STDERR if we're not already logging
+# them at a higher level
+RT->Config->Set( LogToScreen => 'warning')
+ unless ( RT->Config->Get( 'LogToScreen' )
+ && RT->Config->Get( 'LogToScreen' ) =~ /^(debug|info|notice)$/ );
+
+# get customized root password
+my $root_password;
+if ( $args{'root-password-file'} ) {
+ open( my $fh, '<', $args{'root-password-file'} )
+ or die "Couldn't open 'args{'root-password-file'}' for reading: $!";
+ $root_password = <$fh>;
+ chomp $root_password;
+ my $min_length = RT->Config->Get('MinimumPasswordLength');
+ if ($min_length) {
+ die
+"password needs to be at least $min_length long, please check file '$args{'root-password-file'}'"
+ if length $root_password < $min_length;
+ }
+ close $fh;
}
+
# check and setup @actions
my @actions = grep $_, split /,/, $args{'action'};
if ( @actions > 1 && $args{'datafile'} ) {
@@ -124,7 +147,11 @@ foreach ( @actions ) {
# convert init to multiple actions
my $init = 0;
if ( $actions[0] eq 'init' ) {
- @actions = qw(create schema acl coredata insert);
+ if ($args{'skip-create'}) {
+ @actions = qw(schema coredata insert);
+ } else {
+ @actions = qw(create schema acl coredata insert);
+ }
$init = 1;
}
@@ -154,20 +181,25 @@ my $dba_pass = exists($args{'dba-password'})
? $args{'dba-password'}
: $ENV{'RT_DBA_PASSWORD'};
-if ( !$args{force} && ( !defined $dba_pass || $args{'prompt-for-dba-password'} ) ) {
- $dba_pass = get_dba_password();
- chomp $dba_pass if defined($dba_pass);
+if ($args{'skip-create'}) {
+ $dba_user = $db_user;
+ $dba_pass = $db_pass;
+} else {
+ if ( !$args{force} && ( !defined $dba_pass || $args{'prompt-for-dba-password'} ) ) {
+ $dba_pass = get_dba_password();
+ chomp $dba_pass if defined($dba_pass);
+ }
}
print "Working with:\n"
."Type:\t$db_type\nHost:\t$db_host\nName:\t$db_name\n"
- ."User:\t$db_user\nDBA:\t$dba_user\n";
+ ."User:\t$db_user\nDBA:\t$dba_user" . ($args{'skip-create'} ? ' (No DBA)' : '') . "\n";
foreach my $action ( @actions ) {
no strict 'refs';
my ($status, $msg) = *{ 'action_'. $action }{'CODE'}->( %args );
error($action, $msg) unless $status;
- print $msg ."\n" if $msg;
+ print $msg .".\n" if $msg;
print "Done.\n";
}
@@ -215,35 +247,59 @@ sub action_acl {
my ($status, $msg) = RT::Handle->CheckCompatibility( $dbh, 'pre' );
return ($status, $msg) unless $status;
- print "Now inserting database ACLs\n";
+ print "Now inserting database ACLs.\n";
return RT::Handle->InsertACL( $dbh, $args{'datafile'} || $args{'datadir'} );
}
sub action_coredata {
my %args = @_;
- $RT::Handle = new RT::Handle;
+ $RT::Handle = RT::Handle->new;
$RT::Handle->dbh( undef );
RT::ConnectToDatabase();
RT::InitLogging();
my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'pre' );
return ($status, $msg) unless $status;
- print "Now inserting RT core system objects\n";
+ print "Now inserting RT core system objects.\n";
return $RT::Handle->InsertInitialData;
}
sub action_insert {
my %args = @_;
- $RT::Handle = new RT::Handle;
+ $RT::Handle = RT::Handle->new;
RT::Init();
my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'pre' );
return ($status, $msg) unless $status;
- print "Now inserting data\n";
+ print "Now inserting data.\n";
my $file = $args{'datafile'};
$file = $RT::EtcPath . "/initialdata" if $init && !$file;
$file ||= $args{'datadir'}."/content";
- return $RT::Handle->InsertData( $file );
+
+ # Slurp in backcompat
+ my %removed;
+ my @back = @{$args{backcompat} || []};
+ if (@back) {
+ my @lines = do {local @ARGV = @back; <>};
+ for (@lines) {
+ s/\#.*//;
+ next unless /\S/;
+ my ($class, @fields) = split;
+ $class->_BuildTableAttributes;
+ $RT::Logger->debug("Temporarily removing @fields from $class");
+ $removed{$class}{$_} = delete $RT::Record::_TABLE_ATTR->{$class}{$_}
+ for @fields;
+ }
+ }
+
+ my @ret = $RT::Handle->InsertData( $file, $root_password );
+
+ # Put back the fields we chopped off
+ for my $class (keys %removed) {
+ $RT::Record::_TABLE_ATTR->{$class}{$_} = $removed{$class}{$_}
+ for keys %{$removed{$class}};
+ }
+ return @ret;
}
sub action_upgrade {
@@ -262,7 +318,7 @@ sub action_upgrade {
$upgrading_from = scalar <STDIN>;
chomp $upgrading_from;
$upgrading_from =~ s/\s+//g;
- } while $upgrading_from !~ /^\d+\.\d+\.\d+$/;
+ } while $upgrading_from !~ /^\d+\.\d+\.\w+$/;
my $upgrading_to = $RT::VERSION;
return (0, "The current version $upgrading_to is lower than $upgrading_from")
@@ -271,11 +327,16 @@ sub action_upgrade {
return (1, "The version $upgrading_to you're upgrading to is up to date")
if RT::Handle::cmp_version( $upgrading_from, $upgrading_to ) == 0;
- my @versions = get_versions_from_to($base_dir, $upgrading_from, $upgrading_to);
-
- return (1, "No DB changes between $upgrading_from and $upgrading_to")
+ my @versions = get_versions_from_to($base_dir, $upgrading_from, undef);
+ return (1, "No DB changes since $upgrading_from")
unless @versions;
+ if (RT::Handle::cmp_version($versions[-1], $upgrading_to) > 0) {
+ print "\n***** There are upgrades for $versions[-1], which is later than $upgrading_to,\n";
+ print "***** which you are nominally upgrading to. Upgrading to $versions[-1] instead.\n";
+ $upgrading_to = $versions[-1];
+ }
+
print "\nGoing to apply following upgrades:\n";
print map "* $_\n", @versions;
@@ -292,7 +353,7 @@ sub action_upgrade {
chomp $custom_upgrading_to;
$custom_upgrading_to =~ s/\s+//g;
last unless $custom_upgrading_to;
- } while $custom_upgrading_to !~ /^\d+\.\d+\.\d+$/;
+ } while $custom_upgrading_to !~ /^\d+\.\d+\.\w+$/;
if ( $custom_upgrading_to ) {
return (
@@ -322,17 +383,23 @@ sub action_upgrade {
print "\nIT'S VERY IMPORTANT TO BACK UP BEFORE THIS STEP\n\n";
_yesno() or exit(-2) unless $args{'force'};
- foreach my $v ( @versions ) {
+ my ( $ret, $msg );
+ foreach my $n ( 0..$#versions ) {
+ my $v = $versions[$n];
+ my @back = grep {-e $_} map {"$base_dir/$versions[$_]/backcompat"} $n+1..$#versions;
print "Processing $v\n";
- my %tmp = (%args, datadir => "$base_dir/$v", datafile => undef);
+ my %tmp = (%args, datadir => "$base_dir/$v", datafile => undef, backcompat => \@back);
if ( -e "$base_dir/$v/schema.$db_type" ) {
- action_schema( %tmp );
+ ( $ret, $msg ) = action_schema( %tmp );
+ return ( $ret, $msg ) unless $ret;
}
if ( -e "$base_dir/$v/acl.$db_type" ) {
- action_acl( %tmp );
+ ( $ret, $msg ) = action_acl( %tmp );
+ return ( $ret, $msg ) unless $ret;
}
if ( -e "$base_dir/$v/content" ) {
- action_insert( %tmp );
+ ( $ret, $msg ) = action_insert( %tmp );
+ return ( $ret, $msg ) unless $ret;
}
}
return 1;
@@ -346,7 +413,7 @@ sub get_versions_from_to {
closedir $dh;
return
- grep RT::Handle::cmp_version($_, $to) <= 0,
+ grep defined $to ? RT::Handle::cmp_version($_, $to) <= 0 : 1,
grep RT::Handle::cmp_version($_, $from) > 0,
sort RT::Handle::cmp_version @versions;
}
@@ -372,13 +439,10 @@ sub get_dba_password {
return ($password);
}
-=head2 get_system_dbh
-
-Returns L<DBI> database handle connected to B<system> with DBA credentials.
+# get_system_dbh
+# Returns L<DBI> database handle connected to B<system> with DBA credentials.
+# See also L<RT::Handle/SystemDSN>.
-See also L<RT::Handle/SystemDSN>.
-
-=cut
sub get_system_dbh {
return _get_dbh( RT::Handle->SystemDSN, $dba_user, $dba_pass );
@@ -388,13 +452,11 @@ sub get_admin_dbh {
return _get_dbh( RT::Handle->DSN, $dba_user, $dba_pass );
}
-=head2 get_rt_dbh [USER, PASSWORD]
-
-Returns L<DBI> database handle connected to RT database,
-you may specify credentials(USER and PASSWORD) to connect
-with. By default connects with credentials from RT config.
+# get_rt_dbh [USER, PASSWORD]
-=cut
+# Returns L<DBI> database handle connected to RT database,
+# you may specify credentials(USER and PASSWORD) to connect
+# with. By default connects with credentials from RT config.
sub get_rt_dbh {
return _get_dbh( RT::Handle->DSN, $db_user, $db_pass );
@@ -423,54 +485,106 @@ sub _yesno {
$x =~ /^y/i;
}
-sub help {
+1;
- print <<EOF;
+__END__
-$0: Set up RT's database
+=head1 NAME
---action init Initialize the database. This is combination of
- multiple actions listed below. Create DB, schema,
- setup acl, insert core data and initial data.
+rt-setup-database - Set up RT's database
- upgrade Apply all needed schema/acl/content updates (will ask
- for version to upgrade from)
+=head1 SYNOPSIS
- create Create the database.
+ rt-setup-database --action ...
- drop Drop the database.
- This will ERASE ALL YOUR DATA
+=head1 OPTIONS
- schema Initialize only the database schema
- To use a local or supplementary datafile, specify it
- using the '--datadir' option below.
+=over
- acl Initialize only the database ACLs
- To use a local or supplementary datafile, specify it
- using the '--datadir' option below.
+=item action
- coredata Insert data into RT's database. This data is required
- for normal functioning of any RT instance.
+Several actions can be combined using comma separated list.
- insert Insert data into RT's database.
- By default, will use RT's installation data.
- To use a local or supplementary datafile, specify it
- using the '--datafile' option below.
+=over
-Several actions can be combined using comma separated list.
+=item init
---datafile /path/to/datafile
---datadir /path/to/ Used to specify a path to find the local
- database schema and acls to be installed.
+Initialize the database. This is combination of multiple actions listed below.
+Create DB, schema, setup acl, insert core data and initial data.
+=item upgrade
---dba dba's username
---dba-password dba's password
---prompt-for-dba-password Ask for the database administrator's password interactively
+Apply all needed schema/acl/content updates (will ask for version to upgrade
+from)
+=item create
-EOF
+Create the database.
-}
+=item drop
-1;
+Drop the database. This will B<ERASE ALL YOUR DATA>.
+
+=item schema
+
+Initialize only the database schema
+
+To use a local or supplementary datafile, specify it using the '--datadir'
+option below.
+
+=item acl
+
+Initialize only the database ACLs
+
+To use a local or supplementary datafile, specify it using the '--datadir'
+option below.
+
+=item coredata
+
+Insert data into RT's database. This data is required for normal functioning of
+any RT instance.
+
+=item insert
+
+Insert data into RT's database. By default, will use RT's installation data.
+To use a local or supplementary datafile, specify it using the '--datafile'
+option below.
+
+=back
+
+=item datafile
+
+file path of the data you want to action on
+
+e.g. C<--datafile /path/to/datafile>
+
+=item datadir
+
+Used to specify a path to find the local database schema and acls to be
+installed.
+
+e.g. C<--datadir /path/to/>
+
+=item dba
+
+dba's username
+
+=item dba-password
+
+dba's password
+
+=item prompt-for-dba-password
+
+Ask for the database administrator's password interactively
+
+=item skip-create
+
+for 'init': skip creating the database and the user account, so we don't need
+administrator privileges
+
+=item root-password-file
+
+for 'init' and 'insert': rather than using the default administrative password
+for RT's "root" user, use the password in this file.
+
+=back