Changeset 554


Ignore:
Timestamp:
11/20/12 16:02:34 (11 years ago)
Author:
Kris Deugau
Message:

/trunk

Work in progress, see #5:
Update allocateBlock() to support new concept for allocation nesting

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/cgi-bin/IPDB.pm

    r547 r554  
    656656## IPDB::allocateBlock()
    657657# Does all of the magic of actually allocating a netblock
    658 # Requires database handle, block to allocate, custid, type, city,
    659 #       description, notes, circuit ID, block to allocate from, private data
     658# Requires a database handle, and a hash containing the block to allocate, routing depth, custid,
     659#   type, city, block to allocate from, and optionally a description, notes, circuit ID,
     660#   and private data
    660661# Returns a success code and optional error message.
    661662sub allocateBlock {
    662   my ($dbh,undef,undef,$custid,$type,$city,$desc,$notes,$circid,$privdata,$nodeid) = @_;
    663 
    664   my $cidr = new NetAddr::IP $_[1];
    665   my $alloc_from = new NetAddr::IP $_[2];
     663  my $dbh = shift;
     664
     665  my %args = @_;
     666
     667  $args{cidr} = new NetAddr::IP $args{cidr};
     668  $args{alloc_from} = new NetAddr::IP $args{alloc_from};
     669
     670  $args{desc} = '' if !$args{desc};
     671  $args{notes} = '' if !$args{notes};
     672  $args{circid} = '' if !$args{circid};
     673  $args{privdata} = '' if !$args{privdata};
     674  $args{vrf} = '' if !$args{vrf};
     675
    666676  my $sth;
    667677
    668   $desc = '' if !$desc;
    669   $notes = '' if !$notes;
    670   $circid = '' if !$circid;
    671   $privdata = '' if !$privdata;
    672 
    673678  # Snag the "type" of the freeblock (alloc_from) "just in case"
    674   $sth = $dbh->prepare("select routed from freeblocks where cidr='$alloc_from'");
     679  $sth = $dbh->prepare("select routed from freeblocks where cidr='$args{alloc_from}'");
    675680  $sth->execute;
    676681  my ($alloc_from_type) = $sth->fetchrow_array;
    677682
    678683  # To contain the error message, if any.
    679   my $msg = "Unknown error allocating $cidr as '$type'";
     684  my $msg = "Unknown error allocating $args{cidr} as '$disp_alloctypes{$args{type}}'";
    680685
    681686  # Enable transactions and error handling
     
    683688  local $dbh->{RaiseError} = 1; # step on our toes by accident.
    684689
    685   if ($type =~ /^.i$/) {
    686     $msg = "Unable to assign static IP $cidr to $custid";
     690  if ($args{type} =~ /^.i$/) {
     691    $msg = "Unable to assign static IP $args{cidr} to $args{custid}";
    687692    eval {
    688       # We have to do this in two parts because otherwise we lose
    689       # the ability to return the IP assigned.  Should that change,
    690       # the commented SQL statement below may become usable.
    691 # update poolips set custid='$custid',city='$city',available='n',
    692 #       description='$desc',notes='$notes',circuitid='$circid'
    693 #       where ip=(select ip from poolips where pool='$alloc_from'
    694 #       and available='y' order by ip limit 1);
    695 
    696       if ($cidr) {
    697         my ($isavail) = $dbh->selectrow_array("SELECT available FROM poolips WHERE ip=?", undef, ($cidr) );
    698         if ($isavail eq 'n') {
    699           die "IP already allocated.  Deallocate and reallocate, or update the entry\n";
    700         }
    701         if (!$isavail) {
    702           die "IP is not in an IP pool.\n";
    703         }
    704       } else {
    705         ($cidr) = $dbh->selectrow_array("SELECT ip FROM poolips WHERE pool=? AND available='y' ORDER BY ip",
    706                 undef, ($alloc_from) );
    707       }
    708       $dbh->do("UPDATE poolips SET custid=?,city=?,available='n',description=?,notes=?,circuitid=?,privdata=? ".
    709         "WHERE ip=?", undef, ($custid, $city, $desc, $notes, $circid, $privdata, $cidr) );
     693      if ($args{cidr}) {        # IP specified
     694        my ($isavail) = $dbh->selectrow_array("SELECT available FROM poolips WHERE ip=?", undef, ($args{cidr}) );
     695        die "IP is not in an IP pool.\n"
     696          if !$isavail;
     697        die "IP already allocated.  Deallocate and reallocate, or update the entry\n"
     698          if $isavail eq 'n';
     699      } else {  # IP not specified, take first available
     700        ($args{cidr}) = $dbh->selectrow_array("SELECT ip FROM poolips WHERE pool=? AND available='y' ORDER BY ip",
     701                undef, ($args{alloc_from}) );
     702      }
     703      $dbh->do("UPDATE poolips SET custid=?,city=?,available='n',description=?,notes=?,circuitid=?,privdata=?,vrf=? ".
     704        "WHERE ip=?", undef, ($args{custid}, $args{city}, $args{desc}, $args{notes}, $args{circid},
     705                $args{privdata}, $args{vrf}, $args{cidr}) );
    710706
    711707# node hack
    712       if ($nodeid && $nodeid ne '') {
    713         $sth = $dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)");
    714         $sth->execute("$cidr",$nodeid);
     708      if ($args{nodeid} && $args{nodeid} ne '') {
     709        $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{cidr}, $args{nodeid}) );
    715710      }
    716711# end node hack
     
    723718      return ('FAIL',$msg);
    724719    } else {
    725       return ('OK',"$cidr");
     720      return ('OK',"$args{cidr}");
    726721    }
    727722
    728723  } else { # end IP-from-pool allocation
    729724
    730     if ($cidr == $alloc_from) {
     725    if ($args{cidr} == $args{alloc_from}) {
    731726      # Easiest case- insert in one table, delete in the other, and go home.  More or less.
    732727      # insert into allocations values (cidr,custid,type,city,desc) and
     
    735730
    736731      eval {
    737         $msg = "Unable to allocate $cidr as '$disp_alloctypes{$type}'";
    738         if ($type eq 'rm') {
    739           $sth = $dbh->prepare("update freeblocks set routed='y',city='$city'".
    740             " where cidr='$cidr'");
    741           $sth->execute;
    742           $sth = $dbh->prepare("insert into routed (cidr,maskbits,city)".
    743                 " values ('$cidr',".$cidr->masklen.",'$city')");
    744           $sth->execute;
     732        $msg = "Unable to allocate $args{cidr} as '$disp_alloctypes{$args{type}}'";
     733
     734        # Munge freeblocks
     735        if ($args{type} =~ /^(.)[mc]$/) {
     736          # special case - block is a routed or container/"reserve" block
     737          my $rtype = $1;
     738          $dbh->do("UPDATE freeblocks SET routed=?,rdepth=rdepth+1,city=?,parent=? WHERE cidr=? AND rdepth=?",
     739                undef, ($rtype, $args{city}, $args{cidr}, $args{cidr}, $args{rdepth}));
    745740        } else {
    746           # common stuff for end-use, dialup, dynDSL, pools, etc, etc.
    747 
    748           # special case - block is a container/"reserve" block
    749           if ($type =~ /^(.)c$/) {
    750             $sth = $dbh->prepare("update freeblocks set routed='$1' where cidr='$cidr'");
    751             $sth->execute;
    752           } else {
    753             # "normal" case
    754             $sth = $dbh->prepare("delete from freeblocks where cidr='$cidr'");
    755             $sth->execute;
    756           }
    757           $sth = $dbh->prepare("insert into allocations".
    758                 " (cidr,custid,type,city,description,notes,maskbits,circuitid,privdata)".
    759                 " values (?,?,?,?,?,?,?,?,?)");
    760           $sth->execute("$cidr", $custid, $type, $city, $desc, $notes, $cidr->masklen, $circid, $privdata);
    761 
    762           # And initialize the pool, if necessary
    763           # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available
    764           # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed.
    765           if ($type =~ /^.p$/) {
    766             $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr";
    767             my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"all");
    768             die $rmsg if $code eq 'FAIL';
    769           } elsif ($type =~ /^.d$/) {
    770             $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr";
    771             my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"normal");
    772             die $rmsg if $code eq 'FAIL';
    773           }
    774 
    775         } # routing vs non-routing netblock
     741          # "normal" case
     742          $dbh->do("DELETE FROM freeblocks WHERE cidr=? AND rdepth=?", undef, ($args{cidr}, $args{rdepth}));
     743        }
     744
     745        # get old freeblocks parent/depth/routed for new entries
     746        my ($fparent) = $dbh->selectrow_array("SELECT parent,city,routed FROM freeblocks".
     747                " WHERE cidr=? AND rdepth=?", undef, ($args{alloc_from}, $args{rdepth}));
     748
     749        # Insert the allocations entry
     750        $dbh->do("INSERT INTO allocations ".
     751                "(cidr,parent,vrf,rdepth,custid,type,city,description,notes,circuitid,privdata)".
     752                " VALUES (?,?,?,?,?,?,?,?,?,?,?)", undef,
     753                ($args{cidr}, $fparent, $args{vrf}, $args{rdepth}, $args{custid}, $args{type}, $args{city},
     754                $args{desc}, $args{notes}, $args{circid}, $args{privdata}) );
     755
     756        # And initialize the pool, if necessary
     757        # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available
     758        # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed.
     759        if ($args{type} =~ /^.p$/) {
     760          $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}";
     761          my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "all");
     762          die $rmsg if $code eq 'FAIL';
     763        } elsif ($args{type} =~ /^.d$/) {
     764          $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}";
     765          my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "normal");
     766          die $rmsg if $code eq 'FAIL';
     767        }
    776768
    777769# node hack
    778       if ($nodeid && $nodeid ne '') {
    779         $sth = $dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)");
    780         $sth->execute("$cidr",$nodeid);
     770      if ($args{nodeid} && $args{nodeid} ne '') {
     771        $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{cidr}, $args{nodeid}) );
    781772      }
    782773# end node hack
     
    794785
    795786      # Hard case.  Allocation is smaller than free block.
    796       my $wantmaskbits = $cidr->masklen;
    797       my $maskbits = $alloc_from->masklen;
     787      my $wantmaskbits = $args{cidr}->masklen;
     788      my $maskbits = $args{alloc_from}->masklen;
    798789
    799790      my @newfreeblocks;        # Holds free blocks generated from splitting the source freeblock.
     
    803794      # block is in, and repeat until the wanted block is equal to one of the halves.
    804795      my $i=0;
    805       my $tmp_from = $alloc_from;       # So we don't munge $alloc_from
     796      my $tmp_from = $args{alloc_from}; # So we don't munge $args{alloc_from}
    806797      while ($maskbits++ < $wantmaskbits) {
    807798        my @subblocks = $tmp_from->split($maskbits);
    808         $newfreeblocks[$i++] = (($cidr->within($subblocks[0])) ? $subblocks[1] : $subblocks[0]);
    809         $tmp_from = ( ($cidr->within($subblocks[0])) ? $subblocks[0] : $subblocks[1] );
     799        $newfreeblocks[$i++] = (($args{cidr}->within($subblocks[0])) ? $subblocks[1] : $subblocks[0]);
     800        $tmp_from = ( ($args{cidr}->within($subblocks[0])) ? $subblocks[0] : $subblocks[1] );
    810801      } # while
    811802
    812803      # Begin SQL transaction block
    813804      eval {
    814         $msg = "Unable to allocate $cidr as '$disp_alloctypes{$type}'";
     805        $msg = "Unable to allocate $args{cidr} as '$disp_alloctypes{$args{type}}'";
     806
     807        # Get old freeblocks parent/depth/routed for new entries
     808        my ($fparent,$fcity,$wasrouted) = $dbh->selectrow_array("SELECT parent,city,routed FROM freeblocks".
     809                " WHERE cidr=? AND rdepth=?", undef, ($args{alloc_from}, $args{rdepth}) );
    815810
    816811        # Delete old freeblocks entry
    817         $sth = $dbh->prepare("delete from freeblocks where cidr='$alloc_from'");
    818         $sth->execute();
    819 
    820         # now we have to do some magic for routing blocks
    821         if ($type eq 'rm') {
    822 
    823           # Insert the new freeblocks entries
    824           # Note that non-routed blocks are assigned to <NULL>
    825           # and use the default value for the routed column ('n')
    826           $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city)".
    827                 " values (?, ?, '<NULL>')");
    828           foreach my $block (@newfreeblocks) {
    829             $sth->execute("$block", $block->masklen);
    830           }
    831 
    832           # Insert the entry in the routed table
    833           $sth = $dbh->prepare("insert into routed (cidr,maskbits,city)".
    834                 " values ('$cidr',".$cidr->masklen.",'$city')");
    835           $sth->execute;
    836           # Insert the (almost) same entry in the freeblocks table
    837           $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
    838                 " values ('$cidr',".$cidr->masklen.",'$city','y')");
    839           $sth->execute;
    840 
    841         } else { # done with alloctype == rm
    842 
    843           # Insert the new freeblocks entries
    844           # Along with some more HairyPerl(TM):
    845           #   if $alloc_type_from is p
    846           #   OR
    847           #   $type matches /^(.)r$/
    848           # inserted value for routed column should match.
    849           # This solves the case of inserting an arbitrary block into a
    850           # "Reserve-for-routed-DSL" block.  Which you really shouldn't
    851           # do in the first place, but anyway...
    852           $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
    853                 " values (?, ?, (select city from routed where cidr >>= '$cidr'),'".
    854                 ( ( ($alloc_from_type =~ /^(p)$/) || ($type =~ /^(.)r$/) ) ? "$1" : 'y')."')");
    855           foreach my $block (@newfreeblocks) {
    856             $sth->execute("$block", $block->masklen);
    857           }
    858           # Special-case for reserve/"container" blocks - generate
    859           # the "extra" freeblocks entry for the container
    860           if ($type =~ /^(.)c$/) {
    861             $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
    862                 " values ('$cidr',".$cidr->masklen.",'$city','$1')");
    863             $sth->execute;
    864           }
    865           # Insert the allocations entry
    866           $sth = $dbh->prepare("insert into allocations (cidr,custid,type,city,".
    867                 "description,notes,maskbits,circuitid,privdata)".
    868                 " values (?,?,?,?,?,?,?,?,?)");
    869           $sth->execute("$cidr", $custid, $type, $city, $desc, $notes, $cidr->masklen, $circid, $privdata);
    870 
    871           # And initialize the pool, if necessary
    872           # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available
    873           # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed.
    874           if ($type =~ /^.p$/) {
    875             $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr";
    876             my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"all");
    877             die $rmsg if $code eq 'FAIL';
    878           } elsif ($type =~ /^.d$/) {
    879             $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr";
    880             my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"normal");
    881             die $rmsg if $code eq 'FAIL';
    882           }
    883 
    884         } # done with netblock alloctype != rm
     812        $dbh->do("DELETE FROM freeblocks WHERE cidr=? AND rdepth=?", undef, ($args{alloc_from}, $args{rdepth}) );
     813
     814        # Insert new list of smaller free blocks left over
     815        $sth = $dbh->prepare("INSERT INTO freeblocks (cidr,city,routed,vrf,parent,rdepth) VALUES (?,?,?,?,?,?)");
     816        foreach my $block (@newfreeblocks) {
     817          $sth->execute($block, $fcity, $wasrouted, $args{vrf}, $fparent, $args{rdepth});
     818        }
     819
     820        # For routed/container types, add a freeblock within the allocated block so we can subdivide it further
     821        if ($args{type} =~ /(.)[mc]/) { # rm and .c types - containers
     822          my $rtype = $1;
     823          $sth->execute($args{cidr}, $args{city}, $rtype, $args{vrf}, $args{cidr}, $args{rdepth}+1);
     824        }
     825
     826        # Insert the allocations entry
     827        $dbh->do("INSERT INTO allocations ".
     828                "(cidr,parent,vrf,rdepth,custid,type,city,description,notes,circuitid,privdata)".
     829                " VALUES (?,?,?,?,?,?,?,?,?,?,?)", undef,
     830                ($args{cidr}, $fparent, $args{vrf}, $args{rdepth}, $args{custid}, $args{type}, $args{city},
     831                $args{desc}, $args{notes}, $args{circid}, $args{privdata}) );
     832
     833        # And initialize the pool, if necessary
     834        # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available
     835        # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed.
     836        if ($args{type} =~ /^.p$/) {
     837          $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}";
     838          my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "all");
     839          die $rmsg if $code eq 'FAIL';
     840        } elsif ($args{type} =~ /^.d$/) {
     841          $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}";
     842          my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "normal");
     843          die $rmsg if $code eq 'FAIL';
     844        }
    885845
    886846# node hack
    887       if ($nodeid && $nodeid ne '') {
    888         $sth = $dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)");
    889         $sth->execute("$cidr",$nodeid);
     847      if ($args{nodeid} && $args{nodeid} ne '') {
     848        $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{cidr}, $args{nodeid}) );
    890849      }
    891850# end node hack
     851
    892852        $dbh->commit;
    893853      }; # end eval
Note: See TracChangeset for help on using the changeset viewer.