File:  [LON-CAPA] / loncom / debugging_tools / modify_config_files.pl
Revision 1.14: download - view: text, annotated - select for diffs
Fri Oct 26 21:39:44 2018 UTC (5 years, 8 months ago) by raeburn
Branches: MAIN
CVS tags: HEAD
- Checking of LON-CAPA repo entry in /etc/apt/sources.list for
  Ubuntu 12, 14, 16, 18.

    1: #!/usr/bin/perl -w
    2: #
    3: # The LearningOnline Network
    4: #
    5: # $Id: modify_config_files.pl,v 1.14 2018/10/26 21:39:44 raeburn Exp $
    6: #
    7: # Copyright Michigan State University Board of Trustees
    8: #
    9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
   10: #
   11: # LON-CAPA is free software; you can redistribute it and/or modify
   12: # it under the terms of the GNU General Public License as published by
   13: # the Free Software Foundation; either version 2 of the License, or
   14: # (at your option) any later version.
   15: #
   16: # LON-CAPA is distributed in the hope that it will be useful,
   17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19: # GNU General Public License for more details.
   20: #
   21: # You should have received a copy of the GNU General Public License
   22: # along with LON-CAPA; if not, write to the Free Software
   23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   24: #
   25: # /home/httpd/html/adm/gpl.txt
   26: #
   27: # http://www.lon-capa.org/
   28: #
   29: ###
   30: 
   31: =pod
   32: 
   33: =head1 NAME
   34: 
   35: B<modify_config_files.pl>
   36: 
   37: =head1 SYNOPSIS
   38: 
   39: This script modifies /etc/my.cnf and one of: /etc/yum.conf 
   40: (for CentOS/Scientific Linux/RHEL >=5), /etc/apt/sources.list
   41: (for Debian/Ubuntu), /etc/sysconfig/rhn/sources (for RHEL4),
   42: and /etc/yum.repos.d/loncapa.repo (Fedora >= 21).
   43: 
   44: =head1 DESCRIPTION
   45: 
   46: This script modifies /etc/my.cnf, /etc/yum.conf, /etc/yum.repos.d/loncapa.repo,
   47: /etc/apt/sources, or /etc/sysconfig/rhn/sources to ensure certain
   48: parameters are set properly.
   49: 
   50: The LON-CAPA yum repositories are added to /etc/yum.conf, 
   51: /etc/yum.repos.d/loncapa.repo, /etc/sysconfig/rhn/sources
   52: and the LON-CAPA apt repositories are added to 
   53: /etc/apt/sources.list.
   54: 
   55: The /etc/my.cnf file is modified to set the wait_timeout to 1 year.  Backup
   56: copies of each file are made in /etc, /etc/apt, and /etc/sysconfig/rhn, as 
   57: appropriate.
   58: 
   59: =cut
   60: 
   61: use strict;
   62: use File::Copy;
   63: use lib '/home/httpd/lib/perl/';
   64: use LONCAPA::Configuration;
   65: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
   66: 
   67: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
   68: my $dist = <DSH>;
   69: chomp($dist);
   70: close(DSH);
   71: 
   72: my $yum_status;
   73: my $loninst = 'http://install.loncapa.org';
   74: my $loninst_re = 'http://install\.loncapa\.org';
   75: if ($dist =~ /^fedora(\d+)$/) {
   76:     my $file = '/etc/yum.conf';
   77:     my $ver = $1;
   78:     my $gpgchk = '0';
   79:     my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa"; 
   80:     my $nobackup;
   81:     if ($ver > 6) {
   82:         $gpgchk = '1';
   83:     }
   84:     if ($ver >= 21) {
   85:         $file = '/etc/yum.repos.d/loncapa.repo';
   86:         $nobackup = 1;
   87:     }
   88:     $yum_status =  
   89:         &update_file($file,
   90:              [{section => 'loncapa-updates-basearch',
   91:                key     => 'name=',
   92:                value   => 'Fedora Core $releasever LON-CAPA $basearch Updates',
   93:            }, {section => 'loncapa-updates-basearch',
   94:                key     => 'baseurl=',
   95:                value   => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
   96:            }, {section => 'loncapa-updates-basearch',
   97:                key     => 'gpgcheck=',
   98:                value   =>  $gpgchk,
   99:            }, {section => 'loncapa-updates-basearch',
  100:                key     => 'gpgkey=',
  101:                value   => $gpg,
  102:            }, {section => 'loncapa-updates-noarch',
  103:                key     => 'name=',
  104:                value   => 'Fedora Core $releasever LON-CAPA noarch Updates',
  105:            }, {section => 'loncapa-updates-noarch',
  106:                key     => 'baseurl=',
  107:                value   => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
  108:            }, {section => 'loncapa-updates-noarch',
  109:                key     => 'gpgcheck=',
  110:                value   => $gpgchk,
  111:            }, {section => 'loncapa-updates-noarch',
  112:                key     => 'gpgkey=',
  113:                value   => $gpg,
  114:            }],$nobackup);
  115: } elsif ($dist =~ /^(rhes|centos|scientific)(\d+)$/) {
  116:     my $type = $1;
  117:     my $ver = $2;
  118:     my $longver = $ver;
  119:     if ($type eq 'rhes') {
  120:         if ($ver == 4) {
  121:             $longver = '4ES';
  122:         } elsif ($ver == 5) {
  123:             $longver = '5Server';
  124:         }
  125:     }
  126:     my %info = (
  127:                  rhes => {
  128:                            title => 'RHEL',
  129:                            path => 'redhat/linux/enterprise/loncapa',
  130:                            gpg => 'versions/redhat/RPM-GPG-KEY-loncapa',
  131:                            gpgchk => 1,
  132:                          },
  133:                  centos => {
  134:                              title => 'CentOS',
  135:                              path => 'centos/loncapa',
  136:                              gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
  137:                              gpgchk => 1,
  138:                            },
  139:                  scientific => {
  140:                                  title => 'Scientific Linux',
  141:                                  path => 'scientific/loncapa',
  142:                                  gpg => 'versions/scientific/RPM-GPG-KEY-loncapa',
  143:                                  gpgchk => 1,
  144:                                },
  145:                );
  146:     if (ref($info{$type}) eq 'HASH') {
  147:         if ($ver > 4) {
  148:             $yum_status =
  149:                 &update_file('/etc/yum.conf',
  150:                      [{section => 'loncapa-updates-basearch',
  151:                        key     => 'name=',
  152:                        value   => $info{$type}{title}.' $releasever LON-CAPA $basearch Updates',
  153:                       }, {section => "loncapa-updates-basearch",
  154:                           key     => 'baseurl=',
  155:                           value   => "$loninst/$info{$type}{path}/".'$releasever/$basearch',
  156:                       }, {section => 'loncapa-updates-basearch',
  157:                           key     => 'gpgcheck=',
  158:                           value   => $info{$type}{gpgchk},
  159:                       }, {section => 'loncapa-updates-basearch',
  160:                           key     => 'gpgkey=',
  161:                           value   => "$loninst/$info{$type}{gpg}",
  162:                       }, {section => 'loncapa-updates-noarch',
  163:                           key     => 'name=',
  164:                           value   => $info{$type}{title}.' $releasever LON-CAPA noarch Updates',
  165:                       }, {section => 'loncapa-updates-noarch',
  166:                           key     => 'baseurl=',
  167:                           value   => "$loninst/$info{$type}{path}/".'$releasever/noarch',
  168:                       }, {section => 'loncapa-updates-noarch',
  169:                           key     => 'gpgcheck=',
  170:                           value   => $info{$type}{gpgchk},
  171:                       }, {section => 'loncapa-updates-noarch',
  172:                           key     => 'gpgkey=',
  173:                           value   => "$loninst/$info{$type}{gpg}",
  174:                       }]);
  175:         } elsif (($type eq 'rhes') && ($ver == 4)) {
  176:             my %rhn = (
  177:                         basearch => { 
  178:                             regexp => '\s*yum\s+loncapa\-updates\-basearch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/\$ARCH',
  179:                             text => "yum loncapa-updates-basearch $loninst/$info{$type}{path}/$longver/".'$ARCH',
  180:                                     },
  181:                         noarch =>  {
  182:                             regexp => '\s*yum\s+loncapa\-updates\-noarch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/noarch',
  183:                             text => "yum loncapa-updates-noarch $loninst/$info{$type}{path}/$longver/noarch",
  184:                                    },
  185:                       );
  186:             $yum_status = &update_rhn_source(\%rhn); 
  187:         }
  188:     }
  189: } elsif ($dist =~ /^(debian|ubuntu)\d+$/) {
  190:     my %apt_get_source = (
  191:                            debian5 => {
  192:                                         regexp => '\s*deb\s+'.$loninst_re.'/debian/\s+lenny\s+main',
  193:                                         text   => "deb $loninst/debian/ lenny main",
  194:                                       },
  195:                            ubuntu6 => {
  196:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+dapper\s+main',
  197:                                         text   => "deb $loninst/ubuntu/ dapper main",
  198:                                       },
  199:                            ubuntu8 => {
  200:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+hardy\s+main',
  201:                                         text   => "deb $loninst/ubuntu/ hardy main",
  202:                                       },
  203:                            ubuntu10 => {
  204:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+lucid\s+main',
  205:                                         text   => "deb $loninst/ubuntu/ lucid main",
  206:                                        },
  207:                            ubuntu12 => {
  208:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+precise\s+main',
  209:                                         text   => "deb $loninst/ubuntu/ precise main",
  210:                                        },
  211:                            ubuntu14 => {
  212:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+trusty\s+main',
  213:                                         text   => "deb $loninst/ubuntu/ trusty main",
  214:                                        },
  215:                            ubuntu16 => {
  216:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+xenial\s+main',
  217:                                         text   => "deb $loninst/ubuntu/ xenial main",
  218:                                        },
  219:                            ubuntu18 => {
  220:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+bionic\s+main',
  221:                                         text   => "deb $loninst/ubuntu/ bionic main",
  222:                                        },
  223:                          );
  224:     my $apt_status;
  225:     if (defined($apt_get_source{$dist})) {
  226:         $apt_status = &update_apt_source($apt_get_source{$dist},);
  227:     }
  228: }
  229: 
  230: my $mysql_global_status =
  231:     &update_file('/etc/my.cnf',
  232:              [{section =>'mysqld',
  233:                key     =>'wait_timeout=',
  234:                value   =>'31536000', }]);
  235: 
  236: my $local_my_cnf = '/home/www/.my.cnf';
  237: if (! -e $local_my_cnf) {
  238:     # Create a file so we can do something with it...
  239:     system("touch $local_my_cnf");
  240: }
  241: my $mysql_www_status =
  242:     &update_file($local_my_cnf,
  243:              [{section =>'client',
  244:                key     =>'user=',
  245:                value   =>'www',},
  246:               {section =>'client',
  247:                key     =>'password=',
  248:                value   =>$loncapa_config->{'lonSqlAccess'}},]);
  249: 
  250: my $exitvalue = 0;
  251: 
  252: if ($mysql_global_status) { $exitvalue = 1; }
  253: 
  254: exit $exitvalue;
  255: 
  256: 
  257: sub update_file {
  258:     my ($file,$newdata,$nobackup) = @_;
  259:     return 1 if (! -e $file);
  260:     unless ($nobackup) {
  261:         my $backup = $file.'.backup';
  262:         if (! copy($file,$backup)) {
  263:             warn "**** Error: Unable to make backup of $file";
  264:             return 0;
  265:         }
  266:     }
  267:     my ($filedata) = &parse_config_file($file);
  268:     if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
  269:     my $modified = 0;
  270:     foreach my $data (@$newdata) {
  271:         my $section = $data->{'section'};
  272:         my $key = $data->{'key'};
  273:         my $value = $data->{'value'};
  274:         my $result = &modify_config_file($filedata,$section,$key,$value);
  275:         if ($result) { $modified = 1; }
  276:     }
  277:     if ($modified) {
  278:         my $result = &write_config_file($file,$filedata);
  279:         if (defined($result)) { warn 'Error:'.$result; return 0; }
  280:     }
  281:     return $modified;
  282: }
  283: 
  284: #################################################################
  285: #################################################################
  286: 
  287: =pod
  288: 
  289: =over 4
  290: 
  291: =item &parse_config_file()
  292: 
  293: Read a configuration file in and parse it into an internal data structure.
  294: 
  295: Input: filename
  296: 
  297: Output: array ref $filedata  OR  scalar error message
  298: 
  299: =back 
  300: 
  301: =cut
  302: 
  303: #################################################################
  304: #################################################################
  305: sub parse_config_file {
  306:     my ($file) = @_;
  307:     open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
  308:     my @Input = <INFILE>;
  309:     close(INFILE);
  310:     my @Structure;
  311:     my %Sections;
  312:     while (my $line = shift(@Input)) {
  313:         chomp($line);
  314:         if ($line =~ /^\[([^\]]*)\]/) {
  315:             my $section_id = $1;
  316:             push(@Structure,'__section__'.$section_id);
  317:             while ($line = shift(@Input)) {
  318:                 chomp($line);
  319:                 if ($line =~ /^\[([^\]]*)\]/) {
  320:                     unshift(@Input,$line);
  321:                     last;
  322:                 } else {
  323:                     push(@{$Sections{$section_id}},$line);
  324:                 }
  325:             }
  326:         } else {
  327:             push(@Structure,$line);
  328:         }
  329:     }
  330:     my $filedata = [\@Structure,\%Sections];
  331:     return $filedata;
  332: }
  333: 
  334: #################################################################
  335: #################################################################
  336: 
  337: =pod
  338: 
  339: =over 4
  340: 
  341: =item
  342: 
  343: Write a configuration file out based on the internal data structure returned
  344: by &parse_config_file
  345: 
  346: Inputs: filename, $filedata (the return value of &parse_config_file
  347: 
  348: Returns: undef on success, scalar error message on failure.
  349: 
  350: =back
  351: 
  352: =cut
  353: 
  354: #################################################################
  355: #################################################################
  356: sub write_config_file {
  357:     my ($file,$filedata) = @_;
  358:     my ($structure,$sections) = @$filedata;
  359:     if (! defined($structure) || ! ref($structure)) {
  360:         return 'Bad subroutine inputs';
  361:     }
  362:     open(OUTPUT,'>'.$file) || return('Unable to open '.$file.' for writing');
  363:     for (my $i=0;$i<scalar(@$structure);$i++) {
  364:         my $line = $structure->[$i];
  365:         chomp($line);
  366:         if ($line =~ /^__section__(.*)$/) {
  367:             my $section_id = $1;
  368:             print OUTPUT ('['.$section_id.']'.$/);
  369:             foreach my $section_line (@{$sections->{$section_id}}) {
  370:                 chomp($section_line);
  371:                 print OUTPUT $section_line.$/;
  372:             }
  373:             # Deal with blank lines
  374:             if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
  375:                 # No need to output a blank line at the end if there is one 
  376:                 # already
  377:             } else {
  378:                 print OUTPUT $/;
  379:             }
  380:         } else {
  381:             print OUTPUT $line.$/;
  382:         }
  383:     }
  384:     close OUTPUT;
  385:     return undef;
  386: }
  387: 
  388: #################################################################
  389: #################################################################
  390: 
  391: =pod
  392: 
  393: =over 4
  394: 
  395: =item &modify_config_file()
  396: 
  397: Modifies the internal data structure of a configuration file to include new
  398: sections and/or new configuration directives.
  399: 
  400: Inputs: $filedata (see &parse_config_file
  401: $section, the [section] the new entry is to reside in.  A value of undef will
  402: cause the "outer" section (as in yum.conf) to be updated (or have the new
  403: value prepended).
  404: $newkey: A line which matches this will be replaced with $newkey.$newvalue
  405: $newvalue: The new value to be placed with the new key.
  406: 
  407: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
  408: 
  409: =back 
  410: 
  411: =cut
  412: 
  413: #################################################################
  414: #################################################################
  415: sub modify_config_file {
  416:     my ($filedata,$section,$newkey,$newvalue)=@_;
  417:     my $modified = 0;    # returned value - set to true if the file is modified
  418:     my ($structure,$sections) = @$filedata;
  419:     if (! defined($newvalue)) {
  420:         $newvalue = '';
  421:     }
  422:     my $newline = $newkey.$newvalue;
  423:     #
  424:     # Determine which array ref gets the item
  425:     my $target;
  426:     if (defined($section)) {
  427:         if (! exists($sections->{$section})) {
  428:             push(@$structure,'__section__'.$section);
  429:             $sections->{$section}=[];
  430:         }
  431:         $target = $sections->{$section};
  432:     } else {
  433:         $target = $structure;
  434:     }
  435:     #
  436:     # Put the item in or update it.
  437:     my $key_is_new = 1;
  438:     for (my $i=0;$i<scalar(@$target);$i++) {
  439:         if ($target->[$i] =~/^$newkey/) {
  440:             if ($target->[$i] ne $newline) {
  441:                 $target->[$i]=$newline;
  442:                 $modified = 1;
  443:             }
  444:             $key_is_new = 0;
  445:             last;
  446:         }
  447:     }
  448:     if ($key_is_new) {
  449:         if (! defined($section)) {
  450:             unshift(@$target,$newline);
  451:         } else {
  452:             # No need to put things after a blank line.
  453:             if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
  454:                 $target->[-1] = $newline;
  455:                 $modified = 1;
  456:             } else {
  457:                 push(@$target,$newline);
  458:                 $modified = 1;
  459:             }
  460:         }
  461:     }
  462:     return $modified;
  463: }
  464: 
  465: #################################################################
  466: #################################################################
  467: 
  468: =pod
  469: 
  470: =over 4
  471: 
  472: =item &update_rhn_source()
  473: 
  474: Modifies the Red Hat 4 sources file which includes repositories used by up2date 
  475: 
  476: Inputs: 
  477: $rhn_items - a reference to hash of a hash containing the regular expression
  478: to test for, and the text string to append to the file, if an entry for the 
  479: LON-CAPA RHEL repository is missing for two cases:
  480: 
  481: (a) basearch
  482: (b) noarch 
  483: 
  484: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
  485: 
  486: =back
  487: 
  488: =cut
  489: 
  490: #################################################################
  491: #################################################################
  492: sub update_rhn_source {
  493:     my ($rhn_items) = @_;
  494:     return 0 if (ref($rhn_items) ne 'HASH');
  495:     return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH'));
  496:     my $file = '/etc/sysconfig/rhn/sources';
  497:     return 0 if (! -e $file);
  498:     my $backup = $file.'.backup';
  499:     if (! copy($file,$backup)) {
  500:         warn "**** Error: Unable to make backup of $file";
  501:         return 0;
  502:     }
  503:     my $result = 0;
  504:     my $fh;
  505:     if (open($fh,"<$file")) {
  506:         my $total = 0;
  507:         my %found;
  508:         foreach my $item (keys(%{$rhn_items})) {
  509:             $found{$item} = 0;
  510:         }
  511:         while(<$fh>) {
  512:             foreach my $item (keys(%{$rhn_items})) {
  513:                 if (ref($rhn_items->{$item}) eq 'HASH') {
  514:                     my $pattern = $rhn_items->{$item}->{regexp};
  515:                     if ($pattern ne '') { 
  516:                         if (m{^$pattern}) {
  517:                             $found{$item} = 1;
  518:                             $total ++;
  519:                         }
  520:                     }
  521:                 }
  522:             }
  523:             last if $total == 2;
  524:         }
  525:         close($fh);
  526:         if ($total < 2) {
  527:             if (open($fh,">>$file")) {
  528:                 foreach my $item (keys(%{$rhn_items})) {
  529:                     unless ($found{$item}) {
  530:                         if (ref($rhn_items->{$item}) eq 'HASH') {
  531:                             if ($rhn_items->{$item}->{text} ne '') {
  532:                                 print $fh "\n".$rhn_items->{$item}->{text}."\n";
  533:                                 $result = 1;
  534:                             }
  535:                         }
  536:                     }
  537:                 }
  538:                 close($fh);
  539:             }
  540:         }
  541:     }
  542:     return $result;
  543: }
  544: 
  545: #################################################################
  546: #################################################################
  547: 
  548: =pod
  549: 
  550: =over 4
  551: 
  552: =item &update_apt_source()
  553: 
  554: Modifies the source.list file which includes repositories used by apt-get
  555: 
  556: Inputs:
  557: $deb_row - a reference to containing the regular expression
  558: to test for, and the text string to append to the file, if an entry for the
  559: LON-CAPA Debian/ or Ubuntu repository is missing.
  560: 
  561: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
  562: 
  563: =back
  564: 
  565: =cut
  566: 
  567: #################################################################
  568: #################################################################
  569: sub update_apt_source {
  570:     my ($deb_row) = @_;
  571:     return 0 if (ref($deb_row) ne 'HASH');
  572:     return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq ''));
  573:     my $file = '/etc/apt/sources.list';
  574:     return 0 if (! -e $file);
  575:     my $backup = $file.'.backup';
  576:     if (! copy($file,$backup)) {
  577:         warn "**** Error: Unable to make backup of $file";
  578:         return 0;
  579:     }
  580:     my $result = 0;
  581:     my $fh;
  582:     if (open($fh,"<$file")) {
  583:         my $found = 0;
  584:         my $pattern = $deb_row->{regexp};
  585:         while(<$fh>) {
  586:             if (m{^$pattern}) {
  587:                 $found = 1;
  588:                 last;
  589:             }
  590:         }
  591:         close($fh);
  592:         if (!$found) {
  593:             if (open($fh,">>$file")) {
  594:                 print $fh "\n".$deb_row->{text}."\n";
  595:                 close($fh);
  596:                 $result = 1;
  597:             }
  598:         }
  599:     }
  600:     return $result;
  601: }
  602: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>