Ignore:
Timestamp:
05/15/13 16:17:00 (11 years ago)
Author:
Kris Deugau
Message:

/branches/stable

Merge SQL changes and other miscellaneous fixes from /trunk through r553.

Location:
branches/stable
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/stable

  • branches/stable/cgi-bin/IPDB.pm

    r593 r594  
    2323@ISA            = qw(Exporter);
    2424@EXPORT_OK    = qw(
    25         %disp_alloctypes %list_alloctypes %def_custids @citylist @poplist @masterblocks
    26         %allocated %free %routed %bigfree %IPDBacl %aclmsg
    27         &initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock &addMaster
    28         &deleteBlock &getBlockData &mailNotify
     25        %disp_alloctypes %list_alloctypes %def_custids @citylist @poplist
     26        %IPDBacl %aclmsg
     27        &initIPDBGlobals &connectDB &finish &checkDBSanity
     28        &addMaster &touchMaster
     29        &listSummary &listMaster &listRBlock &listFree &listPool
     30        &getMasterList &getTypeList &getPoolSelect &findAllocateFrom
     31        &ipParent &subParent &blockParent &getRoutedCity
     32        &allocateBlock &updateBlock &deleteBlock &getBlockData
     33        &getNodeList &getNodeName &getNodeInfo
     34        &mailNotify
    2935        );
    3036
     
    3238%EXPORT_TAGS    = ( ALL => [qw(
    3339                %disp_alloctypes %list_alloctypes %def_custids @citylist @poplist
    34                 @masterblocks %allocated %free %routed %bigfree %IPDBacl %aclmsg
    35                 &initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock
    36                 &addMaster &deleteBlock &getBlockData &mailNotify
     40                %IPDBacl %aclmsg
     41                &initIPDBGlobals &connectDB &finish &checkDBSanity
     42                &addMaster &touchMaster
     43                &listSummary &listMaster &listRBlock &listFree &listPool
     44                &getMasterList &getTypeList &getPoolSelect &findAllocateFrom
     45                &ipParent &subParent &blockParent &getRoutedCity
     46                &allocateBlock &updateBlock &deleteBlock &getBlockData
     47                &getNodeList &getNodeName &getNodeInfo
     48                &mailNotify
    3749                )]
    3850        );
     
    4658our @citylist;
    4759our @poplist;
    48 our @masterblocks;
    49 our %allocated;
    50 our %free;
    51 our %routed;
    52 our %bigfree;
    5360our %IPDBacl;
    5461
     
    113120  }
    114121
    115   # Master block list
    116   $sth = $dbh->prepare("select cidr from masterblocks order by cidr");
    117   $sth->execute;
    118   return (undef,$sth->errstr) if $sth->err;
    119   for (my $i=0; my @data = $sth->fetchrow_array(); $i++) {
    120     $masterblocks[$i] = new NetAddr::IP $data[0];
    121     $allocated{"$masterblocks[$i]"} = 0;
    122     $free{"$masterblocks[$i]"} = 0;
    123     $bigfree{"$masterblocks[$i]"} = 128; # Larger number means smaller block.
    124                                         # Set to 128 to prepare for IPv6
    125     $routed{"$masterblocks[$i]"} = 0;
    126   }
    127 
    128122  # Load ACL data.  Specific username checks are done at a different level.
    129123  $sth = $dbh->prepare("select username,acl from users");
     
    232226  # Wrap all the SQL in a transaction
    233227  eval {
    234     my $sth = $dbh->prepare("select count(*) from masterblocks where cidr <<= '$cidr'");
    235     $sth->execute;
    236     my @data = $sth->fetchrow_array;
    237 
    238     if ($data[0] eq 0) {
     228    my ($mexist) = $dbh->selectrow_array("SELECT cidr FROM masterblocks WHERE cidr <<= ?", undef, ($cidr) );
     229
     230    if (!$mexist) {
    239231      # First case - master is brand-spanking-new.
    240232##fixme: rwhois should be globally-flagable somewhere, much like a number of other things
    241233## maybe a db table called "config"?
    242       $sth = $dbh->prepare("insert into masterblocks (cidr,rwhois) values ('$cidr','y')");
    243       $sth->execute;
     234      $dbh->do("INSERT INTO masterblocks (cidr,rwhois) VALUES (?,?)", undef, ($cidr,'y') );
    244235
    245236# Unrouted blocks aren't associated with a city (yet).  We don't rely on this
    246237# elsewhere though;  legacy data may have traps and pitfalls in it to break this.
    247238# Thus the "routed" flag.
    248 
    249       $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
    250         " values ('$cidr',".$cidr->masklen.",'<NULL>','n')");
    251       $sth->execute;
     239      $dbh->do("INSERT INTO freeblocks (cidr,maskbits,city,routed) VALUES (?,?,?,?)", undef,
     240        ($cidr, $cidr->masklen, '<NULL>', 'n') );
    252241
    253242      # If we get here, everything is happy.  Commit changes.
    254243      $dbh->commit;
    255244
    256     } # new master does not contain existing master(s)
     245    } # done new master does not contain existing master(s)
    257246    else {
    258247
    259248      # collect the master(s) we're going to absorb, and snag the longest netmask while we're at it.
    260249      my $smallmask = $cidr->masklen;
    261       $sth = $dbh->prepare("select cidr as mask from masterblocks where cidr <<= '$cidr'");
    262       $sth->execute;
     250      my $sth = $dbh->prepare("SELECT cidr FROM masterblocks WHERE cidr <<= ?");
     251      $sth->execute($cidr);
    263252      my @cmasters;
    264253      while (my @data = $sth->fetchrow_array) {
     
    279268
    280269      # collect the unrouted free blocks within the new master
    281       $sth = $dbh->prepare("select cidr from freeblocks where ".
    282                 "maskbits>=$smallmask and cidr <<= '$cidr' and routed='n'");
    283       $sth->execute;
     270      $sth = $dbh->prepare("SELECT cidr FROM freeblocks WHERE maskbits <= ? AND cidr <<= ? AND routed = 'n'");
     271      $sth->execute($smallmask, $cidr);
    284272      while (my @data = $sth->fetchrow_array) {
    285273        my $freeblock = new NetAddr::IP $data[0];
     
    293281
    294282      # freeblocks
    295       $sth = $dbh->prepare("delete from freeblocks where cidr <<= ?");
    296       my $sth2 = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed) values (?,?,'<NULL>','n')");
     283      $sth = $dbh->prepare("DELETE FROM freeblocks WHERE cidr <<= ?");
     284      my $sth2 = $dbh->prepare("INSERT INTO freeblocks (cidr,maskbits,city,routed) VALUES (?,?,'<NULL>','n')");
    297285      foreach my $newblock (@blocklist) {
    298         $sth->execute("$newblock");
    299         $sth2->execute("$newblock", $newblock->masklen);
     286        $sth->execute($newblock);
     287        $sth2->execute($newblock, $newblock->masklen);
    300288      }
    301289
    302290      # master
    303       $sth = $dbh->prepare("delete from masterblocks where cidr <<= '$cidr'");
    304       $sth->execute;
    305       $sth = $dbh->prepare("insert into masterblocks (cidr,rwhois) values ('$cidr','y')");
    306       $sth->execute;
     291      $dbh->do("DELETE FROM masterblocks WHERE cidr <<= ?", undef, ($cidr) );
     292      $dbh->do("INSERT INTO masterblocks (cidr,rwhois) VALUES (?,?)", undef, ($cidr, 'y') );
    307293
    308294      # *whew*  If we got here, we likely suceeded.
     
    319305  }
    320306} # end addMaster
     307
     308
     309## IPDB::touchMaster()
     310# Update last-changed timestamp on a master block.
     311sub touchMaster {
     312  my $dbh = shift;
     313  my $master = shift;
     314
     315  local $dbh->{AutoCommit} = 0;
     316  local $dbh->{RaiseError} = 1;
     317
     318  eval {
     319    $dbh->do("UPDATE masterblocks SET mtime=now() WHERE cidr = ?", undef, ($master));
     320    $dbh->commit;
     321  };
     322
     323  if ($@) {
     324    my $msg = $@;
     325    eval { $dbh->rollback; };
     326    return ('FAIL',$msg);
     327  }
     328  return ('OK','OK');
     329} # end touchMaster()
     330
     331
     332## IPDB::listSummary()
     333# Get summary list of all master blocks
     334# Returns an arrayref to a list of hashrefs containing the master block, routed count,
     335# allocated count, free count, and largest free block masklength
     336sub listSummary {
     337  my $dbh = shift;
     338
     339  my $mlist = $dbh->selectall_arrayref("SELECT cidr AS master FROM masterblocks ORDER BY cidr", { Slice => {} });
     340
     341  foreach (@{$mlist}) {
     342    my ($rcnt) = $dbh->selectrow_array("SELECT count(*) FROM routed WHERE cidr <<= ?", undef, ($$_{master}));
     343    $$_{routed} = $rcnt;
     344    my ($acnt) = $dbh->selectrow_array("SELECT count(*) FROM allocations WHERE cidr <<= ?", undef, ($$_{master}));
     345    $$_{allocated} = $acnt;
     346    my ($fcnt) = $dbh->selectrow_array("SELECT count(*) FROM freeblocks WHERE cidr <<= ?".
     347        " AND (routed='y' OR routed='n')", undef, ($$_{master}));
     348    $$_{free} = $fcnt;
     349    my ($bigfree) = $dbh->selectrow_array("SELECT maskbits FROM freeblocks WHERE cidr <<= ?".
     350        " AND (routed='y' OR routed='n') ORDER BY maskbits LIMIT 1", undef, ($$_{master}));
     351##fixme:  should find a way to do this without having to HTMLize the <>
     352    $bigfree = "/$bigfree" if $bigfree;
     353    $bigfree = '<NONE>' if !$bigfree;
     354    $$_{bigfree} = $bigfree;
     355  }
     356  return $mlist;
     357} # end listSummary()
     358
     359
     360## IPDB::listMaster()
     361# Get list of routed blocks in the requested master
     362# Returns an arrayref to a list of hashrefs containing the routed block, POP/city the block is routed to,
     363# allocated count, free count, and largest free block masklength
     364sub listMaster {
     365  my $dbh = shift;
     366  my $master = shift;
     367
     368  my $rlist = $dbh->selectall_arrayref("SELECT cidr AS block,city FROM routed WHERE cidr <<= ? ORDER BY cidr",
     369        { Slice => {} }, ($master) );
     370
     371  foreach (@{$rlist}) {
     372    my ($acnt) = $dbh->selectrow_array("SELECT count(*) FROM allocations WHERE cidr <<= ?", undef, ($$_{block}));
     373    $$_{nsubs} = $acnt;
     374    my ($fcnt) = $dbh->selectrow_array("SELECT count(*) FROM freeblocks WHERE cidr <<= ?".
     375        " AND (routed='y' OR routed='n')", undef, ($$_{block}));
     376    $$_{nfree} = $fcnt;
     377    my ($bigfree) = $dbh->selectrow_array("SELECT maskbits FROM freeblocks WHERE cidr <<= ?".
     378        " AND (routed='y' OR routed='n') ORDER BY maskbits LIMIT 1", undef, ($$_{block}));
     379##fixme:  should find a way to do this without having to HTMLize the <>
     380    $bigfree = "/$bigfree" if $bigfree;
     381    $bigfree = '<NONE>' if !$bigfree;
     382    $$_{lfree} = $bigfree;
     383  }
     384  return $rlist;
     385} # end listMaster()
     386
     387
     388## IPDB::listRBlock()
     389# Gets a list of free blocks in the requested parent/master in both CIDR and range notation
     390# Takes a parent/master and an optional flag to look at routed or unrouted blocks, depending
     391# on whether the master is a direct master or a routed block
     392# Returns an arrayref to a list of hashrefs containing the CIDR and range-notation blocks
     393sub listRBlock {
     394  my $dbh = shift;
     395  my $routed = shift;
     396
     397  # Snag the allocations for this block
     398  my $sth = $dbh->prepare("SELECT cidr,city,type,custid,swip,description".
     399        " FROM allocations WHERE cidr <<= ? ORDER BY cidr");
     400  $sth->execute($routed);
     401
     402  # hack hack hack
     403  # set up to flag swip=y records if they don't actually have supporting data in the customers table
     404  my $custsth = $dbh->prepare("SELECT count(*) FROM customers WHERE custid = ?");
     405
     406  my @blocklist;
     407  while (my ($cidr,$city,$type,$custid,$swip,$desc) = $sth->fetchrow_array()) {
     408    $custsth->execute($custid);
     409    my ($ncust) = $custsth->fetchrow_array();
     410    my %row = (
     411        block => $cidr,
     412        city => $city,
     413        type => $disp_alloctypes{$type},
     414        custid => $custid,
     415        swip => ($swip eq 'y' ? 'Yes' : 'No'),
     416        partswip => ($swip eq 'y' && $ncust == 0 ? 1 : 0),
     417        desc => $desc
     418        );
     419    $row{subblock} = ($type =~ /^.r$/);         # hmf.  wonder why these won't work in the hash declaration...
     420    $row{listpool} = ($type =~ /^.[pd]$/);
     421    push (@blocklist, \%row);
     422  }
     423  return \@blocklist;
     424} # end listRBlock()
     425
     426
     427## IPDB::listFree()
     428# Gets a list of free blocks in the requested parent/master in both CIDR and range notation
     429# Takes a parent/master and an optional "routed or unrouted" flag that defaults to unrouted.
     430# Returns an arrayref to a list of hashrefs containing the CIDR and range-notation blocks
     431# Returns some extra flags in the hashrefs for routed blocks, since those can have several subtypes
     432sub listFree {
     433  my $dbh = shift;
     434  my $master = shift;
     435  my $routed = shift || 'n';
     436
     437  # do it this way so we can waste a little less time iterating
     438  my $sth = $dbh->prepare("SELECT cidr,routed FROM freeblocks WHERE cidr <<= ? AND ".
     439        ($routed eq 'n' ? '' : 'NOT')." routed = 'n' ORDER BY cidr");
     440  $sth->execute($master);
     441  my @flist;
     442  while (my ($cidr,$rtype) = $sth->fetchrow_array()) {
     443    $cidr = new NetAddr::IP $cidr;
     444    my %row = (
     445        fblock => "$cidr",
     446        frange => $cidr->range,
     447        );
     448    if ($routed eq 'y') {
     449      $row{subblock} = ($rtype ne 'y' && $rtype ne 'n');
     450      $row{fbtype} = $rtype;
     451    }
     452    push @flist, \%row;
     453  }
     454  return \@flist;
     455} # end listFree()
     456
     457
     458## IPDB::listPool()
     459#
     460sub listPool {
     461  my $dbh = shift;
     462  my $pool = shift;
     463
     464  my $sth = $dbh->prepare("SELECT ip,custid,available,description,type".
     465        " FROM poolips WHERE pool = ? ORDER BY ip");
     466  $sth->execute($pool);
     467  my @poolips;
     468  while (my ($ip,$custid,$available,$desc,$type) = $sth->fetchrow_array) {
     469    my %row = (
     470        ip => $ip,
     471        custid => $custid,
     472        available => $available,
     473        desc => $desc,
     474        delme => $available eq 'n'
     475        );
     476    push @poolips, \%row;
     477  }
     478  return \@poolips;
     479} # end listPool()
     480
     481
     482## IPDB::getMasterList()
     483# Get a list of master blocks, optionally including last-modified timestamps
     484# Takes an optional flag to indicate whether to include timestamps;
     485#  'm' includes ctime, all others (suggest 'c') do not.
     486# Returns an arrayref to a list of hashrefs
     487sub getMasterList {
     488  my $dbh = shift;
     489  my $stampme = shift || 'm';   # optional but should be set by caller for clarity
     490
     491  my $mlist = $dbh->selectall_arrayref("SELECT cidr AS master".($stampme eq 'm' ? ',mtime' : '').
     492        " FROM masterblocks ORDER BY cidr", { Slice => {} });
     493  return $mlist;
     494} # end getMasterList()
     495
     496
     497## IPDB::getTypeList()
     498# Get an alloctype/description pair list suitable for dropdowns
     499# Takes a flag to determine which general groups of types are returned
     500# Returns an reference to an array of hashrefs
     501sub getTypeList {
     502  my $dbh = shift;
     503  my $tgroup = shift || 'a';    # technically optional, like this, but should
     504                                # really be specified in the call for clarity
     505  my $tlist;
     506  if ($tgroup eq 'p') {
     507    # grouping 'p' - primary allocation types.  These include static IP pools (_d and _p),
     508    # dynamic-allocation ranges (_e), containers (_c), and the "miscellaneous" cn, in, and en types.
     509    $tlist = $dbh->selectall_arrayref("SELECT type,listname FROM alloctypes WHERE listorder < 500 ".
     510        "AND type NOT LIKE '_i' AND type NOT LIKE '_r' ORDER BY listorder", { Slice => {} });
     511  } elsif ($tgroup eq 'c') {
     512    # grouping 'c' - contained types.  These include all static IPs and all _r types.
     513    $tlist = $dbh->selectall_arrayref("SELECT type,listname FROM alloctypes WHERE listorder <= 500 ".
     514        " AND (type LIKE '_i' OR type LIKE '_r') ORDER BY listorder", { Slice => {} });
     515  } else {
     516    # grouping 'a' - all standard allocation types.  This includes everything
     517    # but mm (present only as a formality).  Make this the default.
     518    $tlist = $dbh->selectall_arrayref("SELECT type,listname FROM alloctypes WHERE listorder <= 500 ".
     519        " ORDER BY listorder", { Slice => {} });
     520  }
     521  return $tlist;
     522}
     523
     524
     525## IPDB::getPoolSelect()
     526# Get a list of pools matching the passed city and type that have 1 or more free IPs
     527# Returns an arrayref to a list of hashrefs
     528sub getPoolSelect {
     529  my $dbh = shift;
     530  my $iptype = shift;
     531  my $pcity = shift;
     532
     533  my ($ptype) = ($iptype =~ /^(.)i$/);
     534  return if !$ptype;
     535  $ptype .= '_';
     536
     537  my $plist = $dbh->selectall_arrayref(
     538        "SELECT (SELECT city FROM allocations WHERE cidr=poolips.pool) AS poolcit, ".
     539        "poolips.pool AS poolblock, COUNT(*) AS poolfree FROM poolips,allocations ".
     540        "WHERE poolips.available='y' AND poolips.pool=allocations.cidr ".
     541        "AND allocations.city = ? AND poolips.type LIKE ? ".
     542        "GROUP BY pool", { Slice => {} }, ($pcity, $ptype) );
     543  return $plist;
     544} # end getPoolSelect()
     545
     546
     547## IPDB::findAllocateFrom()
     548# Find free block to add a new allocation from.  (CIDR block version of pool select above, more or less)
     549# Takes
     550#  - mask length
     551#  - allocation type
     552#  - POP city "parent"
     553#  - optional master-block restriction
     554#  - optional flag to allow automatic pick-from-private-network-ranges
     555# Returns a string with the first CIDR block matching the criteria, if any
     556sub findAllocateFrom {
     557  my $dbh = shift;
     558  my $maskbits = shift;
     559  my $type = shift;
     560  my $city = shift;
     561  my $pop = shift;
     562  my %optargs = @_;
     563
     564  my $failmsg = "No suitable free block found\n";
     565
     566## Set up the SQL to find out what freeblock we can (probably) use for an allocation.
     567## Very large systems will require development of a reserve system (possibly an extension
     568## of the reserve-for-expansion concept in https://secure.deepnet.cx/trac/ipdb/ticket/24?)
     569## Also populate a value list for the DBI call.
     570
     571  my @vallist = ($maskbits, ($type eq 'rm' ? 'n' : ($type =~ /^(.)r$/ ? "$1" : 'y')) );
     572  my $sql = "SELECT cidr FROM freeblocks WHERE maskbits <= ? AND routed = ?";
     573
     574  # for PPP(oE) and container types, the POP city is the one attached to the pool.
     575  # individual allocations get listed with the customer city site.
     576  ##fixme:  chain cities to align roughly with a full layer-2 node graph
     577  $city = $pop if $type !~ /^.[pc]$/;
     578  if ($type ne 'rm' && $city) {
     579    $sql .= " AND city = ?";
     580    push @vallist, $city;
     581  }
     582  # Allow specifying an arbitrary full block, instead of a master
     583  if ($optargs{gimme}) {
     584    $sql .= " AND cidr >>= ?";
     585    push @vallist, $optargs{gimme};
     586  }
     587  # if a specific master was requested, allow the requestor to self->shoot(foot)
     588  if ($optargs{master} && $optargs{master} ne '-') {
     589    $sql .= " AND cidr <<= ?" if $optargs{master} ne '-';
     590    push @vallist, $optargs{master};
     591  } else {
     592    # if a specific master was NOT requested, filter out the RFC 1918 private networks
     593    if (!$optargs{allowpriv}) {
     594      $sql .= " AND NOT (cidr <<= '192.168.0.0/16' OR cidr <<= '10.0.0.0/8' OR cidr <<= '172.16.0.0/12')";
     595    }
     596  }
     597  # Sorting and limiting, since we don't (currently) care to provide a selection of
     598  # blocks to carve up.  This preserves something resembling optimal usage of the IP
     599  # space by forcing contiguous allocations and free blocks as much as possible.
     600  $sql .= " ORDER BY maskbits DESC,cidr LIMIT 1";
     601
     602  my ($fbfound) = $dbh->selectrow_array($sql, undef, @vallist);
     603  return $fbfound;
     604} # end findAllocateFrom()
     605
     606
     607## IPDB::ipParent()
     608# Get an IP's parent pool's details
     609# Takes a database handle and IP
     610# Returns a hashref to the parent pool block, if any
     611sub ipParent {
     612  my $dbh = shift;
     613  my $block = shift;
     614
     615  my $pinfo = $dbh->selectrow_hashref("SELECT cidr,custid,type,city,description FROM allocations".
     616        " WHERE cidr >>= ?", undef, ($block) );
     617  return $pinfo;
     618} # end ipParent()
     619
     620
     621## IPDB::subParent()
     622# Get a block's parent's details
     623# Takes a database handle and CIDR block
     624# Returns a hashref to the parent container block, if any
     625sub subParent {
     626  my $dbh = shift;
     627  my $block = shift;
     628
     629  my $pinfo = $dbh->selectrow_hashref("SELECT cidr,custid,type,city,description FROM allocations".
     630        " WHERE cidr >>= ?", undef, ($block) );
     631  return $pinfo;
     632} # end subParent()
     633
     634
     635## IPDB::blockParent()
     636# Get a block's parent's details
     637# Takes a database handle and CIDR block
     638# Returns a hashref to the parent container block, if any
     639sub blockParent {
     640  my $dbh = shift;
     641  my $block = shift;
     642
     643  my $pinfo = $dbh->selectrow_hashref("SELECT cidr,city FROM routed".
     644        " WHERE cidr >>= ?", undef, ($block) );
     645  return $pinfo;
     646} # end blockParent()
     647
     648
     649## IPDB::getRoutedCity()
     650# Get the city for a routed block.
     651sub getRoutedCity {
     652  my $dbh = shift;
     653  my $block = shift;
     654
     655  my ($rcity) = $dbh->selectrow_array("SELECT city FROM routed WHERE cidr = ?", undef, ($block) );
     656  return $rcity;
     657} # end getRoutedCity()
    321658
    322659
     
    362699#       and available='y' order by ip limit 1);
    363700
    364 # If no specific IP was requested, pick the next available one from the pool.
    365       if (!$cidr) {
    366         $sth = $dbh->prepare("select ip from poolips where pool='$alloc_from'".
    367           " and available='y' order by ip");
    368         $sth->execute;
    369 
    370         my @data = $sth->fetchrow_array;
    371         $cidr = $data[0];  # $cidr is already declared when we get here!
    372       }
    373 
    374       $sth = $dbh->prepare("update poolips set custid=?,city=?,".
    375         "available='n',description=?,notes=?,circuitid=?,privdata=?".
    376         " where ip=?");
    377       $sth->execute($custid, $city, $desc, $notes, $circid, $privdata, "$cidr");
     701      if ($cidr) {
     702        my ($isavail) = $dbh->selectrow_array("SELECT available FROM poolips WHERE ip=?", undef, ($cidr) );
     703        if ($isavail eq 'n') {
     704          die "IP already allocated.  Deallocate and reallocate, or update the entry\n";
     705        }
     706        if (!$isavail) {
     707          die "IP is not in an IP pool.\n";
     708        }
     709      } else {
     710        ($cidr) = $dbh->selectrow_array("SELECT ip FROM poolips WHERE pool=? AND available='y' ORDER BY ip",
     711                undef, ($alloc_from) );
     712      }
     713      $dbh->do("UPDATE poolips SET custid=?,city=?,available='n',description=?,notes=?,circuitid=?,privdata=? ".
     714        "WHERE ip=?", undef, ($custid, $city, $desc, $notes, $circid, $privdata, $cidr) );
     715
    378716# node hack
    379717      if ($nodeid && $nodeid ne '') {
     
    382720      }
    383721# end node hack
     722
    384723      $dbh->commit;
    385724    };
    386725    if ($@) {
    387       $msg .= ": '".$sth->errstr."'";
     726      $msg .= ": $@";
    388727      eval { $dbh->rollback; };
    389728      return ('FAIL',$msg);
     
    634973
    635974
     975## IPDB::updateBlock()
     976# Update an allocation
     977# Takes all allocation fields in a hash
     978sub updateBlock {
     979  my $dbh = shift;
     980  my %args = @_;
     981
     982  return ('FAIL', 'Missing block to update') if !$args{block};
     983
     984  # do it all in a transaction
     985  local $dbh->{AutoCommit} = 0;
     986  local $dbh->{RaiseError} = 1;
     987
     988  my @fieldlist;
     989  my @vallist;
     990  foreach ('custid', 'city', 'description', 'notes', 'circuitid', 'privdata') {
     991    if ($args{$_}) {
     992      push @fieldlist, $_;
     993      push @vallist, $args{$_};
     994    }
     995  }
     996
     997  my $updtable = 'allocations';
     998  my $keyfield = 'cidr';
     999  if ($args{type} =~ /^(.)i$/) {
     1000    $updtable = 'poolips';
     1001    $keyfield = 'ip';
     1002  } else {
     1003## fixme:  there's got to be a better way...
     1004    if ($args{swip}) {
     1005      if ($args{swip} eq 'on' || $args{swip} eq '1' || $args{swip} eq 'y') {
     1006        $args{swip} = 'y';
     1007      } else {
     1008        $args{swip} = 'n';
     1009      }
     1010    }
     1011    foreach ('type', 'swip') {
     1012      if ($args{$_}) {
     1013        push @fieldlist, $_;
     1014        push @vallist, $args{$_};
     1015      }
     1016    }
     1017  }
     1018
     1019  return ('FAIL', 'No fields to update') if !@fieldlist;
     1020
     1021  push @vallist, $args{block};
     1022  my $sql = "UPDATE $updtable SET ";
     1023  $sql .= join " = ?, ", @fieldlist;
     1024  $sql .= " = ? WHERE $keyfield = ?";
     1025
     1026  eval {
     1027    # do the update
     1028    $dbh->do($sql, undef, @vallist);
     1029
     1030    if ($args{node}) {
     1031      # done with delete/insert so we don't have to worry about funkyness updating a node ref that isn't there
     1032      $dbh->do("DELETE FROM noderef WHERE block = ?", undef, ($args{block}) );
     1033      $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{block}, $args{node}) );
     1034    }
     1035
     1036    $dbh->commit;
     1037  };
     1038  if ($@) {
     1039    my $msg = $@;
     1040    $dbh->rollback;
     1041    return ('FAIL', $msg);
     1042  }
     1043  return 0;
     1044} # end updateBlock()
     1045
     1046
    6361047## IPDB::deleteBlock()
    6371048# Removes an allocation from the database, including deleting IPs
     
    8431254
    8441255## IPDB::getBlockData()
    845 # Return custid, type, city, and description for a block
     1256# Get CIDR or IP, custid, type, city, circuit ID, description, notes, modification time, private/restricted
     1257# data, for a CIDR block or pool IP
     1258# Also returns SWIP status flag for CIDR blocks
     1259# Takes the block/IP to look up
     1260# Returns an arrayref to a list of hashrefs
    8461261sub getBlockData {
    8471262  my $dbh = shift;
    8481263  my $block = shift;
    8491264
    850   my $sth = $dbh->prepare("select cidr,custid,type,city,description from searchme".
    851         " where cidr='$block'");
    852   $sth->execute();
    853   return $sth->fetchrow_array();
     1265  my $cidr = new NetAddr::IP $block;
     1266
     1267  my $keycol = 'cidr';
     1268  my $blocktable = 'allocations';
     1269  my $poolip = 0;
     1270
     1271  # Pool IP and IPv6 check all in one!  Still needs to be tightened
     1272  # up a little for the as-yet-unhandled case of IPv6 IP pools
     1273  if ($cidr->bits == 32 && $cidr->masklen == 32) {
     1274    $poolip = 1;
     1275    $keycol = 'ip';
     1276    $blocktable = 'poolips';
     1277  }
     1278  my $binfo = $dbh->selectrow_hashref("SELECT $keycol AS block, custid, type, city, circuitid, description,".
     1279        " notes, modifystamp AS lastmod, privdata".($poolip ? '' : ', swip')." FROM $blocktable".
     1280        " WHERE $keycol = ?", undef, ($block) );
     1281  return $binfo;
    8541282} # end getBlockData()
     1283
     1284
     1285## IPDB::getNodeList()
     1286# Gets a list of node ID+name pairs as an arrayref to a list of hashrefs
     1287sub getNodeList {
     1288  my $dbh = shift;
     1289 
     1290  my $ret = $dbh->selectall_arrayref("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id",
     1291        { Slice => {} });
     1292  return $ret;
     1293} # end getNodeList()
     1294
     1295
     1296## IPDB::getNodeName()
     1297# Get node name from the ID
     1298sub getNodeName {
     1299  my $dbh = shift;
     1300  my $nid = shift;
     1301
     1302  my ($nname) = $dbh->selectrow_array("SELECT node_name FROM nodes WHERE node_id = ?", undef, ($nid) );
     1303  return $nname;
     1304} # end getNodeName()
     1305
     1306
     1307## IPDB::getNodeInfo()
     1308# Get node name and ID associated with a block
     1309sub getNodeInfo {
     1310  my $dbh = shift;
     1311  my $block = shift;
     1312
     1313  my ($nid, $nname) = $dbh->selectrow_array("SELECT nodes.node_id,node_name FROM nodes INNER JOIN noderef".
     1314        " ON nodes.node_id=noderef.node_id WHERE noderef.block = ?", undef, ($block) );
     1315  return ($nid, $nname);
     1316} # end getNodeInfo()
    8551317
    8561318
Note: See TracChangeset for help on using the changeset viewer.