Changeset 702 for trunk/cgi-bin/IPDB.pm


Ignore:
Timestamp:
02/23/15 18:16:11 (9 years ago)
Author:
Kris Deugau
Message:

/trunk

Add "split block" feature. See #7. May still need a little tweaking
("List IPs" link for pools, refiddle rDNS template records?)

Also stubbed out "shrink block" (branch for "split block"), and added
a placeholder for "merge blocks".

File:
1 edited

Legend:

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

    r699 r702  
    3232        &getMasterList &getTypeList &getPoolSelect &findAllocateFrom
    3333        &ipParent &subParent &blockParent &getBreadCrumbs &getRoutedCity
    34         &allocateBlock &updateBlock &deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP
     34        &allocateBlock &updateBlock &splitBlock &deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP
    3535        &getNodeList &getNodeName &getNodeInfo
    3636        &mailNotify
     
    4747                &getMasterList &getTypeList &getPoolSelect &findAllocateFrom
    4848                &ipParent &subParent &blockParent &getBreadCrumbs &getRoutedCity
    49                 &allocateBlock &updateBlock &deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP
     49                &allocateBlock &updateBlock &splitBlock &deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP
    5050                &getNodeList &getNodeName &getNodeInfo
    5151                &mailNotify
     
    14531453
    14541454
     1455## IPDB::splitBlock()
     1456# Splits an existing allocation into two or more smaller allocations based on a passed netmask
     1457# Duplicates all other data
     1458# Returns an arrayref to a list of hashrefs with ID and CIDR keys for the list of new allocations.
     1459# Should probably commit DNS magic to realign DNS data
     1460sub splitBlock {
     1461  my $dbh = shift;
     1462  my $id = shift;
     1463  my $basetype = shift;
     1464  my $newmask = shift;
     1465
     1466##fixme:  set errstr on errors so caller can suitably clue-by-four the user
     1467  return if $basetype ne 'b';  # only netblocks allowed!
     1468
     1469  my $binfo = getBlockData($dbh, $id);
     1470  return if !$binfo;
     1471
     1472  return if $newmask !~ /^\d+$/;
     1473
     1474  my @ret;
     1475  my $block = new NetAddr::IP $binfo->{block};
     1476  my $oldmask = $block->masklen;
     1477
     1478  # Fail if the block to split is "too small" - eg, can't split a v4 /32 at all
     1479  # failure modes:
     1480  # difference between $oldmask and $newmask is negative or 0
     1481  if ($newmask - $oldmask <= 0) {
     1482    $errstr = "Can't split a /$oldmask allocation into /$newmask pieces";
     1483    return;
     1484  }
     1485#  # difference between $oldmask and $newmask is > n, for arbitrary n?
     1486#  if ($newmask - $oldmask > 42) {  # because 42
     1487#  }
     1488  # $oldmask > n, for arbitrary n?  At least check limits of data type.
     1489  if ($block->{isv6}) {
     1490    if ($newmask - $oldmask > 128) {
     1491      $errstr = "Impossible IPv6 mask length /$newmask requested";
     1492      return;
     1493    }
     1494  } else {
     1495    if ($newmask - $oldmask > 32) {
     1496      $errstr = "Impossible IPv4 mask length /$newmask requested";
     1497      return;
     1498    }
     1499  }
     1500
     1501  my @newblocks = $block->split($newmask);
     1502
     1503  local $dbh->{AutoCommit} = 0;
     1504  local $dbh->{RaiseError} = 1;
     1505
     1506  eval {
     1507    # line up a list of fields and values.  Be nice if there was a handy way to do,
     1508    # direct in SQL, something like
     1509    # "INSERT INTO foo (f1,f2,f3) VALUES (newf1,(SELECT oldf2,oldf3 FROM foo WHERE baz))"
     1510    my @fieldlist = qw(type city description notes circuitid privdata custid swip vrf vlan rdns parent_id master_id);
     1511    my $fields_sql = join(',', @fieldlist);
     1512    my @vals;
     1513    foreach (@fieldlist) {
     1514      push @vals, $binfo->{$_};
     1515    }
     1516    # note the first block in the split for return
     1517    push @ret, {nid => $id, nblock => "$newblocks[0]"};
     1518
     1519    # prepare
     1520    my $idsth = $dbh->prepare("SELECT currval('allocations_id_seq')");
     1521    my $poolsth = $dbh->prepare("INSERT INTO allocations (cidr, $fields_sql)".
     1522        " VALUES (?".',?'x(scalar(@fieldlist)).")");
     1523    my $poolchildsth = $dbh->prepare("UPDATE poolips SET parent_id = ? WHERE ip << ? AND parent_id = ?");
     1524    my $nbsth = $dbh->prepare("DELETE FROM poolips WHERE parent_id = ? AND ip = ?");
     1525
     1526    # set up update of existing block
     1527    $dbh->do("UPDATE allocations SET cidr = ? WHERE id = ?", undef, ("$newblocks[0]", $id) );
     1528
     1529    # axe the net, gw, and bcast IPs as necessary when splitting a "normal" pool
     1530    if ($binfo->{type} =~ /.d/) {
     1531      $newblocks[0]--;
     1532      $nbsth->execute($id, $newblocks[0]->addr);
     1533    }
     1534
     1535    # Loop over the new blocks that are not the base block
     1536    for (my $i = 1; $i <= $#newblocks; $i++) {
     1537      # add the new pool
     1538      $poolsth->execute($newblocks[$i], @vals);
     1539      # fetch the ID of the entry we just added...
     1540      $idsth->execute();
     1541      my ($nid) = $idsth->fetchrow_array();
     1542      # ... so we can pass back the list of blocks and IDs...
     1543      push @ret, {nid => $nid, nblock => "$newblocks[$i]"};
     1544      # axe the net, gw, and bcast IPs as necessary when splitting a "normal" pool
     1545      if ($binfo->{type} =~ /.d/) {
     1546        # net
     1547        $nbsth->execute($id, $newblocks[$i]->addr);
     1548        $newblocks[$i]++;
     1549        # gw
     1550        $nbsth->execute($id, $newblocks[$i]->addr);
     1551        $newblocks[$i]--;
     1552        $newblocks[$i]--;
     1553        # bcast
     1554        $nbsth->execute($id, $newblocks[$i]->addr);
     1555        $newblocks[$i]++;
     1556      }
     1557      # ... and update the existing IPs with the new parent_id
     1558      $poolchildsth->execute($nid, $newblocks[$i], $id);
     1559    }
     1560
     1561    $dbh->commit;
     1562  };
     1563  if ($@) {
     1564    $errstr = "Error splitting $binfo->{block}: $@";
     1565    $dbh->rollback;
     1566    return;
     1567  }
     1568
     1569  return \@ret;
     1570} # end splitBlock()
     1571
     1572
    14551573## IPDB::deleteBlock()
    14561574# Removes an allocation from the database, including deleting IPs
Note: See TracChangeset for help on using the changeset viewer.