7a3c2a8f97f0c080dfec78d3b26e2e4a0c6fecbb
[working/Evergreen.git] / Open-ILS / src / support-scripts / eg_db_config.pl
1 #!/usr/bin/perl
2 # eg_db_config.pl -- configure Evergreen database settings and create schema
3 # vim:noet:ts=4:sw=4:
4 #
5 # Copyright (C) 2008 Equinox Software, Inc.
6 # Copyright (C) 2008-2009 Laurentian University
7 # Author: Kevin Beswick <kevinbeswick00@gmail.com>
8 # Author: Dan Scott <dscott@laurentian.ca>
9 #
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License
12 # as published by the Free Software Foundation; either version 2
13 # of the License, or (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19
20 use strict; use warnings;
21 use XML::LibXML;
22 use File::Copy;
23 use Getopt::Long;
24 use File::Spec;
25 use File::Basename;
26 use DBI;
27
28 my ($dbhost, $dbport, $dbname, $dbuser, $dbpw, $help, $admin_user, $admin_pw);
29 my $config_file = '';
30 my $build_db_sh = '';
31 my $offline_file = '';
32 my $prefix = '';
33 my $sysconfdir = '';
34 my $pg_contribdir = '';
35 my $create_db_sql = '';
36 my @services;
37
38 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
39
40 # Get the directory for this script
41 my $script_dir = dirname($0);
42
43 =over
44
45 =item update_config() - Puts command line specified settings into xml file
46 =cut
47 sub update_config {
48         my ($services, $settings) = @_;
49
50         my $parser = XML::LibXML->new();
51         my $opensrf_config = $parser->parse_file($config_file);
52
53         if (@$services) {
54                 foreach my $service (@$services) {
55                         foreach my $key (keys %$settings) {
56                                 next unless $settings->{$key};
57                                 my @node;
58
59                                 if ($service eq 'state_store') {
60                                         (@node) = $opensrf_config->findnodes("//state_store/$key/text()");
61                                 } else {
62                                         (@node) = $opensrf_config->findnodes("//$service//database/$key/text()");
63                                 }
64
65                                 foreach (@node) {
66                                         $_->setData($settings->{$key});
67                                 }
68                         }
69
70                 }
71         }
72
73         my $timestamp = sprintf("%d.%d.%d.%d.%d.%d",
74                 $year + 1900, $mon +1, $mday, $hour, $min, $sec);
75         if (copy($config_file, "$config_file.$timestamp")) {
76                 print "Backed up original configuration file to '$config_file.$timestamp'\n";
77         } else {
78                 print STDERR "Unable to write to '$config_file.$timestamp'; bailed out.\n";
79         }
80
81         $opensrf_config->toFile($config_file) or
82                 die "ERROR: Failed to update the configuration file '$config_file'\n";
83 }
84
85 =item create_offline_config() - Write out the offline config
86 =cut
87 sub create_offline_config {
88         my ($setup, $settings) = @_;
89
90         open(FH, '>', $setup) or die "Could not write offline database setup to $setup\n";
91
92         print "Writing offline database configuration to $setup\n";
93
94         printf FH "\$main::config{base_dir} = '%s/var/data/offline/';\n", $prefix;
95         printf FH "\$main::config{bootstrap} = '%s/opensrf_core.xml';\n", $sysconfdir;
96
97         printf FH "\$main::config{dsn} = 'dbi:Pg:host=%s;dbname=%s;port=%d';\n",
98                 $settings->{host}, $settings->{db}, $settings->{port};
99
100         printf FH "\$main::config{usr} = '%s';\n", $settings->{user};
101         printf FH "\$main::config{pw} = '%s';\n", $settings->{pw};
102
103         close(FH);
104 }
105
106 =item get_settings() - Extracts database settings from opensrf.xml
107 =cut
108 sub get_settings {
109         my $settings = shift;
110
111         my $host = "/opensrf/default/apps/open-ils.storage/app_settings/databases/database/host/text()";
112         my $port = "/opensrf/default/apps/open-ils.storage/app_settings/databases/database/port/text()";
113         my $dbname = "/opensrf/default/apps/open-ils.storage/app_settings/databases/database/db/text()";
114         my $user = "/opensrf/default/apps/open-ils.storage/app_settings/databases/database/user/text()";
115         my $pw = "/opensrf/default/apps/open-ils.storage/app_settings/databases/database/pw/text()";
116
117         my $parser = XML::LibXML->new();
118         my $opensrf_config = $parser->parse_file($config_file);
119
120         # If the user passed in settings at the command line,
121         # we don't want to override them
122         $settings->{host} = $settings->{host} || $opensrf_config->findnodes($host);
123         $settings->{port} = $settings->{port} || $opensrf_config->findnodes($port);
124         $settings->{db} = $settings->{db} || $opensrf_config->findnodes($dbname);
125         $settings->{user} = $settings->{user} || $opensrf_config->findnodes($user);
126         $settings->{pw} = $settings->{pw} || $opensrf_config->findnodes($pw);
127 }
128
129 =item create_database() - Creates the database using create_database.sql
130 =cut
131 sub create_database {
132         my $settings = shift;
133
134         $ENV{'PGUSER'} = $settings->{user};
135         $ENV{'PGPASSWORD'} = $settings->{pw};
136         $ENV{'PGPORT'} = $settings->{port};
137         $ENV{'PGHOST'} = $settings->{host};
138         my $cmd = 'psql -vdb_name=' . $settings->{db} . ' -vcontrib_dir=' . $pg_contribdir .
139                 ' -d postgres -f ' . $create_db_sql;
140         system($cmd);
141 }
142
143 =item create_schema() - Creates the database schema by calling build-db.sh
144 =cut
145 sub create_schema {
146         my $settings = shift;
147
148         chdir(dirname($build_db_sh));
149         my $cmd = File::Spec->catfile('.', basename($build_db_sh)) . " " .
150                 $settings->{host} ." ".  $settings->{port} ." ". 
151                 $settings->{db} ." ".  $settings->{user} ." ". 
152                 $settings->{pw};
153         system($cmd);
154         chdir($script_dir);
155 }
156
157 =item set_admin_account() - Sets the administrative user's user name and password
158 =cut
159 sub set_admin_account {
160         my $admin_user = shift;
161         my $admin_pw = shift;
162         my $settings = shift;
163
164         my $dbh = DBI->connect('dbi:Pg:dbname=' . $settings->{db} . 
165                 ';host=' . $settings->{host} . ';port=' . $settings->{port} . ';',
166                  $settings->{user} . "", $settings->{pw} . "", {AutoCommit => 1}
167         );
168         if ($dbh->err) {
169                 print STDERR "Could not connect to database to set admin account. ";
170                 print STDERR "Error was " . $dbh->errstr . "\n";
171                 return;
172         }
173         my $stmt = $dbh->prepare("UPDATE actor.usr SET usrname = ?, passwd = ? WHERE id = 1");
174         $stmt->execute(($admin_user, $admin_pw));
175         if ($dbh->err) {
176                 print STDERR "Failed to set admin account. ";
177                 print STDERR "Error was " . $dbh->errstr . "\n";
178                 return;
179         }
180 }
181
182 my $offline;
183 my $cdatabase;
184 my $cschema;
185 my $uconfig;
186 my $pgconfig;
187 my %settings;
188
189 GetOptions("create-schema" => \$cschema, 
190                 "create-database" => \$cdatabase,
191                 "create-offline" => \$offline,
192                 "update-config" => \$uconfig,
193                 "config-file=s" => \$config_file,
194                 "build-db-file=s" => \$build_db_sh,
195                 "pg-contrib-dir=s" => \$pg_contribdir,
196                 "create-db-sql=s" => \$create_db_sql,
197                 "pg-config" => \$pgconfig,
198                 "admin-user=s" => \$admin_user,
199                 "admin-password=s" => \$admin_pw,
200                 "service=s" => \@services,
201                 "user=s" => \$settings{'user'},
202                 "password=s" => \$settings{'pw'},
203                 "database=s" => \$settings{'db'},
204                 "hostname=s" => \$settings{'host'},
205                 "port=i" => \$settings{'port'}, 
206                 "help" => \$help
207 );
208
209 if (grep(/^all$/, @services)) {
210         @services = qw/reporter open-ils.cstore open-ils.pcrud open-ils.storage open-ils.reporter-store state_store/;
211 }
212
213 my $eg_config = File::Spec->catfile($script_dir, '../extras/eg_config');
214
215 if (!$config_file) { 
216         my @temp = `$eg_config --sysconfdir`;
217         chomp $temp[0];
218         $sysconfdir = $temp[0];
219         $config_file = File::Spec->catfile($sysconfdir, "opensrf.xml");
220 }
221
222 if (!$prefix) {
223         my @temp = `$eg_config --prefix`;
224         chomp $temp[0];
225         $prefix = $temp[0];
226 }
227
228 if (!$build_db_sh) {
229         $build_db_sh = File::Spec->catfile($script_dir, '../sql/Pg/build-db.sh');
230 }
231
232 if (!$pg_contribdir) {
233         $pgconfig = 'pg_config' if(!$pgconfig);
234         my @temp = `$pgconfig --sharedir`;
235         chomp $temp[0];
236         $pg_contribdir = File::Spec->catdir($temp[0], 'contrib');
237 }
238
239 if (!$create_db_sql) {
240         $create_db_sql = File::Spec->catfile($script_dir, '../sql/Pg/create_database.sql');
241 }
242
243 if (!$offline_file) {
244         $offline_file = File::Spec->catfile($sysconfdir, 'offline-config.pl');
245 }
246
247 unless (-e $build_db_sh) { die "Error: $build_db_sh does not exist. \n"; }
248 unless (-e $config_file) { die "Error: $config_file does not exist. \n"; }
249 unless (-d $pg_contribdir || !$cdatabase) { die "Error: $pg_contribdir does not exist. \n"; }
250
251 if ($uconfig) { update_config(\@services, \%settings); }
252
253 # Get our settings from the config file
254 get_settings(\%settings);
255
256 if ($cdatabase) { create_database(\%settings); }
257 if ($cschema) { create_schema(\%settings); }
258 if ($admin_user && $admin_pw) {
259         set_admin_account($admin_user, $admin_pw, \%settings);
260 }
261 if ($offline) { create_offline_config($offline_file, \%settings); }
262
263 if ((!$cdatabase && !$cschema && !$uconfig && !$offline && !$admin_pw) || $help) {
264         print <<HERE;
265
266 SYNOPSIS
267     eg_db_config.pl [OPTION] ... [COMMAND] ... [CONFIG OPTIONS]
268
269 DESCRIPTION
270     Creates or recreates the Evergreen database schema based on the settings
271     in the opensrf.xml configuration file.
272
273     Manipulates the configuration file 
274
275 OPTIONS
276     --config-file
277         specifies the opensrf.xml file. Defaults to /openils/conf/opensrf.xml
278
279     --build-db-file
280         specifies the script that creates the database schema. Defaults to
281         Open-ILS/src/sql/pg/build-db.sh
282
283     --offline-file
284         specifies the offline database settings file required by the offline
285         data uploader. Defaults to /openils/conf/offline-config.pl
286
287 COMMANDS
288     --update-config
289         Configures Evergreen database settings in the file specified by
290         --build-db-file.  
291
292     --create-offline
293         Creates the database setting file required by the offline data uploader
294
295     --create-schema
296         Creates the Evergreen database schema according to the settings in
297         the file specified by --config-file.  
298
299     --create-database
300         Creates the database itself, provided the user and password options
301         represent a superuser.
302
303 SERVICE OPTIONS
304     --service
305         Specify "all" or one or more of the following services to update:
306             * reporter
307             * open-ils.cstore
308             * open-ils.pcrud
309             * open-ils.storage
310             * open-ils.reporter-store
311             * state_store
312     
313 DATABASE CONFIGURATION OPTIONS
314     --user            username for the database 
315
316     --password        password for the user 
317
318     --database        name of the database 
319
320     --hostname        name or address of the database host 
321
322     --port            port number for database access
323
324     --admin-user      administration user's user name
325
326     --admin-pass      administration user's password
327
328 EXAMPLES
329    This script is normally used during the initial installation and
330    configuration process. This creates the database schema, sets
331    the administration user's user name and password, and modifies your
332    configuration files to include the correct database connection
333    information.
334
335    For a single server install, or an install with one web/application
336    server and one database server, you will typically want to invoke this
337    script with a complete set of commands:
338
339    perl Open-ILS/src/support-scripts/eg_db_config.pl --update-config \
340        --service all --create-schema --create-offline \
341        --user <db-user> --password <db-pass> --hostname localhost --port 5432 \
342        --database evergreen --admin-user <admin-user> --admin-pass <admin-pass> 
343
344    To update the configuration for a single service - for example, if you
345    replicated a database for reporting purposes - just issue the
346    --update-config command with the service identified and the changed
347    database parameters specified:
348
349    perl Open-ILS/src/support-scripts/eg_db_config.pl --update-config \
350        --service reporter --hostname foobar --password newpass
351
352 HERE
353 }