From 5c9dde4da24396c92b2e88a9297460004f6fe638 Mon Sep 17 00:00:00 2001 From: miker Date: Fri, 29 Jun 2007 03:55:37 +0000 Subject: [PATCH 1/1] Patch from Dan Scott to move perl OpenSRF core bootstrapping settings into opensrf_core.xml. This removes the dependency on the INI style bootstrap.conf file: Building on Nathan Eady's suggestion / intention from December (http://list.georgialibraries.org/pipermail/open-ils-dev/2006-December/000177.html), here is a patch that enables OpenSRF to avoid duplicating settings in opensrf_core.xml and bootstrap.conf by having both Perl and C apps read from opensrf_core.xml The major limitation is that I've hardcoded /config/opensrf to appear as the 'bootstrap' section of config for compatibility with the expectations of the rest of OpenSRF. A broader patch would convert all of those other calls from config->bootstrap->blah to config->opensrf->blah and make the siblings of /config/opensrf visible in the config as well, as a more generally useful approach. Applied with minor changes to avoid API regressions and remove unneeded code. git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@982 9efc2488-bf62-4759-914b-345cdb29e865 --- bin/osrf_ctl.sh | 21 +-- examples/opensrf_core.xml.example | 13 +- src/perlmods/OpenSRF/Utils/Config.pm | 235 +++++++++++---------------- src/perlmods/OpenSRF/Utils/Logger.pm | 19 +-- 4 files changed, 120 insertions(+), 168 deletions(-) diff --git a/bin/osrf_ctl.sh b/bin/osrf_ctl.sh index 531d6df..374385d 100755 --- a/bin/osrf_ctl.sh +++ b/bin/osrf_ctl.sh @@ -1,8 +1,7 @@ #!/bin/bash OPT_ACTION="" -OPT_PERL_CONFIG="" -OPT_C_CONFIG="" +OPT_CONFIG="" OPT_PID_DIR="" # --------------------------------------------------------------------------- @@ -11,12 +10,9 @@ OPT_PID_DIR="" [ $(whoami) != 'opensrf' ] && echo 'Must run as user "opensrf"' && exit; -# NOTE: Eventually, there will be one OpenSRF config file format -# When this happens, we will only need a single OPT_CONFIG variable - function usage { echo ""; - echo "usage: $0 -d -p -c -a "; + echo "usage: $0 -d -c -a "; echo ""; echo "Actions include:" echo -e "\tstart_router" @@ -36,7 +32,7 @@ function usage { echo -e "\trestart_all" echo ""; echo "Example:"; - echo " $0 -p bootstrap.conf -c opensrf_core.xml -a restart_all"; + echo " $0 -c opensrf_core.xml -a restart_all"; echo ""; exit; } @@ -45,11 +41,10 @@ function usage { # --------------------------------------------------------------------------- # Load the command line options and set the global vars # --------------------------------------------------------------------------- -while getopts "p:c:a:d:h" flag; do +while getopts "c:a:d:h" flag; do case $flag in "a") OPT_ACTION="$OPTARG";; - "c") OPT_C_CONFIG="$OPTARG";; - "p") OPT_PERL_CONFIG="$OPTARG";; + "c") OPT_CONFIG="$OPTARG";; "d") OPT_PID_DIR="$OPTARG";; "h"|*) usage;; esac; @@ -110,7 +105,7 @@ function do_action { function start_router { do_action "start" $PID_ROUTER "OpenSRF Router"; - opensrf_router $OPT_C_CONFIG router + opensrf_router $OPT_CONFIG router pid=$(ps ax | grep "OpenSRF Router" | grep -v grep | awk '{print $1}') echo $pid > $PID_ROUTER; return 0; @@ -123,7 +118,7 @@ function stop_router { function start_perl { do_action "start" $PID_OSRF_PERL "OpenSRF Perl"; - perl -MOpenSRF::System="$OPT_PERL_CONFIG" -e 'OpenSRF::System->bootstrap()' & + perl -MOpenSRF::System="$OPT_CONFIG" -e 'OpenSRF::System->bootstrap()' & pid=$!; echo $pid > $PID_OSRF_PERL; sleep 5; @@ -143,7 +138,7 @@ function start_c { fi; do_action "start" $PID_OSRF_C "OpenSRF C (host=$host)"; - opensrf-c $host $OPT_C_CONFIG opensrf; + opensrf-c $host $OPT_CONFIG opensrf; pid=$(ps ax | grep "OpenSRF System-C" | grep -v grep | awk '{print $1}') echo $pid > "$PID_OSRF_C"; return 0; diff --git a/examples/opensrf_core.xml.example b/examples/opensrf_core.xml.example index 98875ac..708d4a6 100644 --- a/examples/opensrf_core.xml.example +++ b/examples/opensrf_core.xml.example @@ -2,7 +2,7 @@ - + @@ -17,7 +17,7 @@ - + localhost @@ -41,8 +41,10 @@ 3 - + + /openils/conf/opensrf.xml + @@ -58,7 +60,6 @@ /openils/var/log/osrfsys.log - @@ -140,7 +141,3 @@ - - - - diff --git a/src/perlmods/OpenSRF/Utils/Config.pm b/src/perlmods/OpenSRF/Utils/Config.pm index 427c28d..9b21221 100755 --- a/src/perlmods/OpenSRF/Utils/Config.pm +++ b/src/perlmods/OpenSRF/Utils/Config.pm @@ -26,58 +26,17 @@ sub new { $self = bless {}, $class; - my $lines = shift; - - for my $line (@$lines) { - - #($line) = split(/\s+\/\//, $line); - #($line) = split(/\s+#/, $line); - - if ($line =~ /^\s*\[([^\[\]]+)\]/) { - $self->_sub_builder('__id'); - $self->__id( $1 ); - next; - } + $self->_sub_builder('__id'); + # Hard-code this to match old bootstrap.conf section name + $self->__id('bootstrap'); - my ($protokey,$value,$keytype,$key); - if ($line =~ /^([^=\s]+)\s*=\s*(.*)\s*$/s) { - ($protokey,$value) = ($1,$2); - ($keytype,$key) = split(/:/,$protokey); - } - - $key = $protokey unless ($key); - - if ($keytype ne $key) { - $keytype = lc $keytype; - if ($keytype eq 'list') { - $value = [split /\s*,\s*/, $value]; - } elsif ($keytype eq 'bool') { - $value = do{ $value =~ /^t|y|1/i ? 1 : 0; }; - } elsif ($keytype eq 'interval') { - $value = interval_to_seconds($value); - } elsif ($keytype eq 'subsection') { - if (exists $SECTIONCACHE{$value}) { - $value = $SECTIONCACHE{$value}; - } else { - $SUBSECTION_FIXUP{$value}{$self->SECTION} = $key ; - next; - } - } - } + my $bootstrap = shift; + foreach my $key (sort keys %$bootstrap) { $self->_sub_builder($key); - $self->$key($value); - } - - no warnings; - if (my $parent_def = $SUBSECTION_FIXUP{$self->SECTION}) { - my ($parent_section, $parent_key) = each %$parent_def; - $SECTIONCACHE{$parent_section}->{$parent_key} = $self; - delete $SUBSECTION_FIXUP{$self->SECTION}; + $self->$key($bootstrap->{$key}); } - $SECTIONCACHE{$self->SECTION} = $self; - return $self; } @@ -87,6 +46,7 @@ use vars qw/@ISA $AUTOLOAD $VERSION $OpenSRF::Utils::ConfigCache/; push @ISA, qw/OpenSRF::Utils/; use FileHandle; +use XML::LibXML; use OpenSRF::Utils (':common'); use OpenSRF::Utils::Logger; use Net::Domain qw/hostfqdn/; @@ -157,9 +117,9 @@ OpenSRF::Utils::Config my $config_obj = OpenSRF::Utils::Config->load( config_file => '/config/file.cnf' ); - my $attrs_href = $config_obj->attributes(); + my $attrs_href = $config_obj->bootstrap(); - $config_obj->attributes->no_db(0); + $config_obj->bootstrap->loglevel(0); open FH, '>'.$config_obj->FILE() . '.new'; print FH $config_obj; @@ -170,61 +130,56 @@ OpenSRF::Utils::Config =head1 DESCRIPTION -This module is mainly used by other modules to load a configuration file. +This module is mainly used by other OpenSRF modules to load an OpenSRF configuration file. +OpenSRF configuration files are XML files that contain a C<< >> root element and an C<< >> +child element (in XPath notation, C). Each child element is converted into a +hash key=>value pair. Elements that contain other XML elements are pushed into arrays and added +as an array reference to the hash. Scalar values have whitespace trimmed from the left and right +sides. + +Child elements of C<< >> other than C<< >> are currently ignored by this module. + +=head1 EXAMPLE +Given an OpenSRF configuration file named F with the following content: + + + + + router + + + localhost + otherhost + + + /openils/var/log/osrfsys.log + + + +... calling C<< OpenSRF::Utils::Config->load(config_file => 'opensrf_core.xml') >> will create a hash +with the following structure: + + { + router_name => 'router', + routers => ['localhost', 'otherhost'], + logfile => '/openils/var/log/osrfsys.log' + } + +You can retrieve any of these values by name from the bootstrap section of C<$config_obj>; for example: + + $config_obj->bootstrap->router_name =head1 NOTES - +For compatibility with a previous version of OpenSRF configuration files, the F section +has a hardcoded name of B. However, future iterations of this module may extend the ability +of the module to parse the entire OpenSRF configuration file and provide sections named after the sibling +elements of C. + Hashrefs of sections can be returned by calling a method of the object of the same name as the section. They can be set by passing a hashref back to the same method. Sections will B be autovivicated, though. -Here be a config file example, HAR!: - - [datasource] - # backend=XMLRPC - backend=DBI - subsection:definition=devel_db - - [devel_db] - dsn=dbi:Pg(RaiseError => 0, AutoCommit => 1):dbname=dcl;host=nsite-dev - user=postgres - pw=postgres - #readonly=1 - - [live_db] - dsn=dbi:Pg(RaiseError => 0, AutoCommit => 1):dbname=dcl - user=n2dcl - pw=dclserver - #readonly=1 - - [devel_xmlrpc] - subsection:definition=devel_rpc - - [logs] - base=/var/log/nsite - debug=debug.log - error=error.log - - [debug] - enabled=1 - level=ALL - - [devel_rpc] - url=https://localhost:9000/ - proto=SSL - SSL_cipher_list=ALL - SSL_verify_mode=5 - SSL_use_cert=1 - SSL_key_file=client-key.pem - SSL_cert_file=client-cert.pem - SSL_ca_file=cacert.pem - log_level=4 - - [dirs] - base_dir=/home/miker/cvs/NOC/monitor_core/ - cert_dir=certs/ - =head1 METHODS @@ -358,60 +313,56 @@ sub mangle_dirs { sub load_config { my $self = shift; - my $config = new FileHandle $self->FILE, 'r'; + my $parser = XML::LibXML->new(); + + # Hash of config values + my %bootstrap; + + # Return an XML::LibXML::Document object + my $config = $parser->parse_file($self->FILE); + unless ($config) { OpenSRF::Utils::Logger->error("Could not open ".$self->FILE.": $!\n"); die "Could not open ".$self->FILE.": $!\n"; } - my @stripped_config = $self->__strip_comments($config) if (defined $config); - - my $chunk = []; - for my $line (@stripped_config) { - no warnings; - next unless ($line); - if ($line =~ /^\s*\[/ and @$chunk) { - my $section = $self->section_pkg->new($chunk); + # Return an XML::LibXML::NodeList object matching all child elements + # of ... + my $osrf_cfg = $config->findnodes('/config/opensrf/child::*'); - my $sub_name = $section->SECTION; - $self->_sub_builder($sub_name); - $self->$sub_name($section); + # Iterate through the nodes to pull out key=>value pairs of config settings + foreach my $node ($osrf_cfg->get_nodelist()) { + my $child_state = 0; - #$self->{$section->SECTION} = $section; + # This will be overwritten if it's a scalar setting + $bootstrap{$node->nodeName()} = []; - $chunk = []; - push @$chunk,$line; - next; - } - if ($line =~ /^#\s*include\s+"(\S+)"\s*$/o) { - my $included_file = $1; - my $section = OpenSRF::Utils::Config->load(config_file => $included_file, nocache => 1); + foreach my $child_node ($node->childNodes) { + # from libxml/tree.h: nodeType 1 = ELEMENT_NODE + next if $child_node->nodeType() != 1; - my $sub_name = $section->FILE; - $self->_sub_builder($sub_name); - $self->$sub_name($section); - - for my $subsect (keys %$section) { - next if ($subsect eq '__id'); - - $self->_sub_builder($subsect); - $self->$subsect($$section{$subsect}); - - #$self->$subsect($section->$subsect); - $self->$subsect->{__sub} = 1; - } - next; + # If the child node is an element, this element may + # have multiple values; therefore, push it into an array + push @{$bootstrap{$node->nodeName()}}, OpenSRF::Utils::Config::extract_text($child_node->textContent); + $child_state = 1; + } + if (!$child_state) { + $bootstrap{$node->nodeName()} = OpenSRF::Utils::Config::extract_text($node->textContent); } - - push @$chunk,$line; } - my $section = $self->section_pkg->new($chunk) if (@$chunk); + + my $section = $self->section_pkg->new(\%bootstrap); my $sub_name = $section->SECTION; $self->_sub_builder($sub_name); $self->$sub_name($section); } +sub extract_text { + my $self = shift; + $self =~ s/^\s*([.*?])\s*$//m; + return $self; +} #------------------------------------------------------------------------------------------------------------------------------------ @@ -419,13 +370,25 @@ sub load_config { OpenSRF::Utils +=head1 LIMITATIONS + +Elements containing heterogeneous child elements are treated as though they have the same element name; +for example: + + localhost + chair + + +... will simply generate a key=>value pair of C<< routers => ['localhost', 'chair'] >>. + =head1 BUGS -No know bugs, but report any to mrylander@gmail.com. +No known bugs, but report any to open-ils-dev@list.georgialibraries.org or mrylander@gmail.com. =head1 COPYRIGHT AND LICENSING -Mike Rylander, Copyright 2000-2007 +Copyright (C) 2000-2007, Mike Rylander +Copyright (C) 2007, Laurentian University, Dan Scott The OpenSRF::Utils::Config module is free software. You may distribute under the terms of the GNU General Public License version 2 or greater. diff --git a/src/perlmods/OpenSRF/Utils/Logger.pm b/src/perlmods/OpenSRF/Utils/Logger.pm index bbeff7a..138aa01 100644 --- a/src/perlmods/OpenSRF/Utils/Logger.pm +++ b/src/perlmods/OpenSRF/Utils/Logger.pm @@ -39,7 +39,6 @@ my $syslog_enabled = 0; # is syslog enabled? my $act_syslog_enabled = 0; # is syslog enabled? my $logfile_enabled = 1; # are we logging to a file? my $act_logfile_enabled = 1; # are we logging to a file? -my $logdir; # log file directory our $logger = "OpenSRF::Utils::Logger"; @@ -66,16 +65,14 @@ sub set_config { warn "*** Logger found no config. Using STDERR ***\n"; } - $loglevel = $config->bootstrap->debug; - if($loglevel =~ /error/i){ $loglevel = ERROR(); } - elsif($loglevel =~ /warn/i){ $loglevel = WARN(); } - elsif($loglevel =~ /info/i){ $loglevel = INFO(); } - elsif($loglevel =~ /debug/i){ $loglevel = DEBUG(); } - elsif($loglevel =~ /internal/i){ $loglevel = INTERNAL(); } + $loglevel = $config->bootstrap->loglevel; + if($loglevel = 1){ $loglevel = ERROR(); } + elsif($loglevel = 2){ $loglevel = WARN(); } + elsif($loglevel = 3){ $loglevel = INFO(); } + elsif($loglevel = 4){ $loglevel = DEBUG(); } + elsif($loglevel = 5){ $loglevel = INTERNAL(); } else{$loglevel= INFO(); } - my $logdir = $config->bootstrap->log_dir; - $logfile = $config->bootstrap->logfile; if($logfile =~ /^syslog/) { $syslog_enabled = 1; @@ -86,7 +83,7 @@ sub set_config { $facility = _fac_to_const($facility); openlog($service, 0, $facility); - } else { $logfile = "$logdir/$logfile"; } + } else { $logfile = "$logfile"; } $actfile = $config->bootstrap->actlog; if($actfile =~ /^syslog/) { @@ -97,7 +94,7 @@ sub set_config { $actfile = undef; $actfac = _fac_to_const($actfac); - } else { $actfile = "$logdir/$actfile"; } + } else { $actfile = "$actfile"; } $isclient = (OpenSRF::Utils::Config->current->bootstrap->client =~ /^true$/iog) ? 1 : 0; } -- 2.43.2