Changeset 836 for trunk


Ignore:
Timestamp:
04/20/22 17:28:23 (2 years ago)
Author:
Kris Deugau
Message:

/trunk

Enhance compact-recs.pl with a --replace option for somewhat easier repeat calling

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/compact-recs.pl

    r835 r836  
    2222use strict;
    2323use warnings;
     24use Getopt::Long;
    2425
    2526# Taint-safe (ish) voodoo to push "the directory the script is in" into @INC.
     
    4142
    4243sub usage {
    43   die qq(usage:  compact-recs.pl netblock pattern
    44     netblock  the CIDR block to define the A+PTR template on
    45     pattern   the pattern to define the new A+PTR template with, and
    46               to match A+PTR records within the netblock for deletion
     44  die qq(usage:  compact-recs.pl netblock pattern [--replace [record id]]
     45    netblock   the CIDR block to define the A+PTR template on
     46    pattern    the pattern to define the new A+PTR template with, and
     47               to match A+PTR records within the netblock for deletion
     48    --replace  Optional argument to update an existing template if found.
     49               A record ID can be specified to match a particular record,
     50               or 'all' to forcibly remove all but one in the event of
     51               multiple records.  If multiple records are found but neither
     52               'all' or a specific record ID is specified, an error will be
     53               returned and nothing will be changed since there is no
     54               guarantee of which record might be replaced.
     55
    4756        OR
    4857        compact-recs.pl --batch patternfile
    4958    patternfile should be a file containing a list of netblock-pattern
    50     pairs, whitespace separated
     59    pairs, whitespace separated.  --replace is ignored in this mode.
    5160
    5261    A PTR template record will be created instead of an A+PTR template
     
    5463    the database.
    5564
    56     WARNING:  Multiple runs will result in duplicate template records.
     65    WARNING:  Multiple runs may result in duplicate template records.
    5766);
     67}
     68
     69my $batchmode = 0;
     70my $replace = 0;
     71my $tmpl_msg = '';
     72
     73GetOptions("batch" => \$batchmode,
     74        "replace:s" => \&setreplace );
     75
     76sub setreplace {
     77  if ($_[1] eq '') {
     78    $replace = -1;
     79  } else {
     80    $replace = $_[1];
     81  }
     82}
     83
     84if ($replace && $replace !~ /^(all|-?\d+)$/) {
     85  warn "Invalid --replace argument $replace:\n";
     86  usage();
    5887}
    5988
     
    7099$dnsdb->{logfullname} = ($dnsdb->{logfullname} ? $dnsdb->{logfullname}."/compact-recs.pl" : $dnsdb->{logusername});
    71100
    72 if ($ARGV[0] eq '--batch') {
    73   open NBLIST, "<$ARGV[1]";
     101if ($batchmode) {
     102  # --replace not safe for --batch.  could arguably support an in-file flag someday?
     103  if ($replace) {
     104    $replace = 0;
     105    warn "--replace not compatible with --batch.  Attempting to continue.\n";
     106  }
     107  open NBLIST, "<$ARGV[0]";
    74108  while (<NBLIST>) {
    75109    next if /^#/;
     
    94128  $dbh->{RaiseError} = 1;
    95129
    96   my ($zonecidr,$zone,$ploc) = $dbh->selectrow_array("SELECT revnet,rdns_id,default_location FROM revzones WHERE revnet >>= ?",
    97         undef, ($cidr) );
     130  my ($zonecidr,$zone,$ploc) = $dbh->selectrow_array(
     131      "SELECT revnet,rdns_id,default_location FROM revzones WHERE revnet >>= ?",
     132      undef, ($cidr) );
    98133  if (!$zone) {
    99134    warn "$cidr is not within a zone currently managed here.\n";
     
    102137  my $soa = $dnsdb->getSOA('n', 'y', $zone);
    103138  my $dparent = $dnsdb->_hostparent($patt) || 0;
     139  # Automatically choose new type as A+PTR template if the new pattern's
     140  # domain is managed in this instance, or PTR template if not
    104141  my $newtype = ($dparent ? 65283 : 65282);
    105142
    106   my ($istmpl) = $dbh->selectrow_array("SELECT count(*) FROM records WHERE rdns_id = ? AND ".
    107         "(type=65282 OR type=65283) AND val = ?", undef, ($zone, $cidr) );
    108   if ($istmpl) {
    109     print "Template already exists for $cidr, manual cleanup required\n";
     143  my ($tmplcount) = $dbh->selectrow_array("SELECT count(*) FROM records WHERE rdns_id = ? AND ".
     144      "(type=65282 OR type=65283) AND val = ?", undef, ($zone, $cidr) );
     145  if ($tmplcount && !$replace) {
     146    # Template(s) found, --replace not set
     147    print "One or more templates found for $cidr, use --replace [record_id],".
     148        " --replace all, or clean up manually.\n";
     149    return;
     150  } elsif ($tmplcount > 1 && ($replace eq '0' || $replace eq '-1')) {
     151    # Multiple templates found, --replace either not set (==0) or no argument provided (==-1)
     152    print "Multiple templates found matching $cidr but no record ID specified with".
     153        " --replace.  Use --replace with a record ID, use --replace all, or clean up".
     154        " manually.\n";
    110155    return;
    111156  }
     
    117162    # First, clean up the records that match the template.
    118163    my $getsth = $dbh->prepare("SELECT record_id,host,val FROM records ".
    119         "WHERE (type = 12 OR type > 65000) AND inetlazy(val) << ? AND rdns_id = ?");
     164        "WHERE (type = 12 OR type > 65000) AND inetlazy(val) << ? AND rdns_id = ?");
    120165    my $delsth = $dbh->prepare("DELETE FROM records WHERE record_id = ?");
    121166    $getsth->execute($cidr, $zone);
     
    128173    }
    129174
    130     $dbh->do("INSERT INTO records (domain_id, rdns_id, host, type, val, ttl, location) VALUES (?,?,?,?,?,?,?)",
     175    my $template_modified = 0;
     176
     177    if ($replace) {
     178      if ($replace eq 'all') {
     179        # clear any templates with the same CIDR, and add a new one
     180        $dbh->do("DELETE from records WHERE rdns_id = ? AND (type=65282 OR type=65283) AND val = ?", undef, ($zone, $cidr) );
     181        $dbh->do("INSERT INTO records (domain_id, rdns_id, host, type, val, ttl, location) VALUES (?,?,?,?,?,?,?)",
     182            undef, ($dparent, $zone, $patt, $newtype, $cidr, $soa->{minttl}, $ploc) );
     183        $template_modified = 1;
     184        $tmpl_msg = ", replaced $tmplcount template records";
     185      } else {
     186        if ($replace =~ /^\d+$/) {
     187          # $replace == [id] -> replace that record ID, error if it doesn't exist or isn't
     188          # a template for the specified CIDR.  Arguably some stretch on the latter.
     189          my ($rechost,$recval,$rectype) = $dbh->selectrow_array(
     190              "SELECT host,val,type,record_id FROM records WHERE record_id = ?",
     191              undef, $replace);
     192          if (($rectype == 65282 || $rectype == 65283) && $recval eq $cidr) {
     193            # Do the update if the record specified matches is a suitable template
     194            $dbh->do("UPDATE records SET host = ?, type = ?, val = ? WHERE record_id = ?",
     195                undef, ($patt, $newtype, $cidr, $replace) );
     196            $template_modified = 1;
     197            $tmpl_msg = ", replaced an existing template record";
     198          } else {
     199            # Specified record ID isn't a template record, or doesn't match $cidr, or both
     200            die "Specified record ID isn't a template for $cidr, skipping:\n".
     201                "  $replace found:  $rechost $typemap{$rectype} $recval\n";
     202          }
     203        } else {
     204          # $replace == -1 -> replace/update template iff one template is present
     205          #   (should have errored out earlier if multiple templates are present)
     206          my ($rechost,$recval,$rectype,$recid) = $dbh->selectrow_array(
     207              "SELECT host,val,type,record_id FROM records WHERE rdns_id = ? AND (type=65282 OR type=65283) AND val = ?",
     208              undef, ($zone, $cidr) );
     209          if ($recid) {
     210            # Do the update if we've found an existing template with the same CIDR
     211            $dbh->do("UPDATE records SET host = ?, type = ?, val = ? WHERE record_id = ?",
     212                undef, ($patt, $newtype, $cidr, $recid) );
     213            $template_modified = 1;
     214            $tmpl_msg = ", replaced an existing template record";
     215          } else {
     216            $dbh->do("INSERT INTO records (domain_id, rdns_id, host, type, val, ttl, location) VALUES (?,?,?,?,?,?,?)",
     217                undef, ($dparent, $zone, $patt, $newtype, $cidr, $soa->{minttl}, $ploc) );
     218            $template_modified = 1;
     219          }
     220        } # $replace -> [id] or $replace == -1
     221      } # $replace <> 'all'
     222    } else {
     223      # $replace == 0 (not set), just insert the new template
     224      $dbh->do("INSERT INTO records (domain_id, rdns_id, host, type, val, ttl, location) VALUES (?,?,?,?,?,?,?)",
    131225        undef, ($dparent, $zone, $patt, $newtype, $cidr, $soa->{minttl}, $ploc) );
    132     $dbh->do("UPDATE revzones SET changed='y' WHERE rdns_id = ?", undef, ($zone));
    133     $dbh->do("UPDATE domains SET changed='y' WHERE domain_id = ?", undef, ($dparent)) if $dparent;
    134     $dnsdb->_log(rdns_id => $zone, domain_id => $dparent, group_id => 1,
    135         entry => "A+PTR and/or PTR records in $cidr matching $patt replaced by $typemap{$newtype} record for $cidr");
    136 
    137     $dbh->commit;
     226      $template_modified = 1;
     227    }
     228
     229    if ($template_modified) {
     230      my %logdata = (rdns_id => $zone, domain_id => $dparent, group_id => 1,
     231          entry => "A+PTR and/or PTR records in $cidr matching $patt replaced by $typemap{$newtype} record for $cidr");
     232      $dnsdb->_updateserial(%logdata);
     233      $dnsdb->_log(%logdata);
     234      $dbh->commit;
     235    } else {
     236      # no need to do push out a null update that just bumps the serial on the zone(s)
     237      $dbh->rollback;
     238    }
     239
    138240  };
    139241  if ($@) {
    140     print "barf: $@\n";
     242    print "Error(s) encountered: $@\n";
    141243    $dbh->rollback;
    142244    return;
    143245  }
    144   print " complete ($delcnt records)\n";
     246  print " complete (removed $delcnt PTR/A+PTR records";
     247  print $tmpl_msg;
     248  print ")\n";
    145249} # squashem ()
Note: See TracChangeset for help on using the changeset viewer.