Ability to clean rack and drop entire row from UI
authorVladimir Sukhonosov <xornet@yandex-team.ru>
Sun, 31 May 2015 18:28:57 +0000 (21:28 +0300)
committerVladimir Sukhonosov <xornet@yandex-team.ru>
Wed, 3 Jun 2015 11:18:42 +0000 (14:18 +0300)
Now you can drop entire row even if it filled with racks
In that case UI will drop all the racks and row itself

Another ability is to clean rack mounts from UI (tab Properties in the
rack page). There is new 'Action' button - 'cleanup'. The button will
reset all mount points in the current rack

new database.php functions:
commitCleanRack ($rack_id)
commitDeleteRack ($rack_id)
commitDeleteRow ($row_id)
getRowMountsCount ($row_id)
getRackMountsCount ($rack_id)

new ophandler: rack-edit-cleanRack

ChangeLog
wwwroot/inc/database.php
wwwroot/inc/interface.php
wwwroot/inc/navigation.php
wwwroot/inc/ophandlers.php

index 52a0a2d..799eb23 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,8 @@
        new feature: VLAN domain groups.
                A group is a domain that has all the VLANs of its members
        update: SNMP support for Cisco Nexus 3132Q
+       update: ability to clean rack mounts or drop entire row (even if it contains racks inside)
+               from user interface
 0.20.10 2015-01-26
        bugfix: port type could not be changed for an unlinked modular port (#1393)
        bugfix: crash on object's rackspace page when PHP < 5.3 (array_replace is missing)
index f6509f3..f93aaa1 100644 (file)
@@ -1455,6 +1455,72 @@ function commitUpdateRack ($rack_id, $new_row_id, $new_name, $new_height, $new_h
        commitUpdateObject ($rack_id, $new_name, NULL, $new_has_problems, $new_asset_no, $new_comment);
 }
 
+// Unmount all objects from the rack
+function commitCleanRack ($rack_id)
+{
+       $rack = spotEntity ('rack', $rack_id);
+       foreach (getChildren ($rack, 'object') as $child)
+               commitUnlinkEntities ('rack', $rack_id, 'object', $child['id']);
+       usePreparedDeleteBlade ('RackSpace', array ('rack_id' => $rack_id));
+       usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
+}
+
+// Drop the rack
+function commitDeleteRack ($rack_id)
+{
+       $rack = spotEntity ('rack', $rack_id);
+       releaseFiles ('rack', $rack_id);
+       destroyTagsForEntity ('rack', $rack_id);
+       usePreparedDeleteBlade ('RackSpace', array ('rack_id' => $rack_id));
+       commitDeleteObject ($rack_id);
+       foreach (getParents ($rack, 'row') as $row)
+               resetRackSortOrder ($row['id']);
+}
+
+// Drop the row with all racks inside
+function commitDeleteRow ($row_id)
+{
+       $racks = getRacks ($row_id);
+       foreach ($racks as $rack)
+               commitDeleteRack ($rack['id']);
+       commitDeleteObject ($row_id);
+}
+
+// Returns mounted devices count in all racks inside the specified row
+function getRowMountsCount ($row_id)
+{
+       $query =<<<END
+SELECT COUNT(*) FROM (
+       SELECT object_id FROM RackSpace rs LEFT JOIN EntityLink el ON (rs.rack_id = el.child_entity_id)
+       WHERE
+               rs.object_id IS NOT NULL AND
+               el.parent_entity_id = ? AND el.parent_entity_type = "row" AND el.child_entity_type = "rack"
+       UNION
+       SELECT el1.child_entity_id object_id FROM EntityLink el1 LEFT JOIN EntityLink el2 ON (el1.parent_entity_id = el2.child_entity_id)
+       WHERE
+               el1.parent_entity_type = "rack" AND el1.child_entity_type = "object" AND
+               el2.parent_entity_id = ? AND el2.parent_entity_type = "row" AND el2.child_entity_type = "rack"
+) x
+END;
+       $result = usePreparedSelectBlade ($query, array ($row_id, $row_id));
+       return $result->fetch (PDO::FETCH_COLUMN, 0);
+}
+
+// Returns mounted devices count in specified rack
+function getRackMountsCount ($rack_id)
+{
+       $query =<<<END
+SELECT COUNT(*) FROM (
+       SELECT object_id FROM RackSpace WHERE object_id IS NOT NULL AND rack_id = ?
+       UNION
+       SELECT child_entity_id object_id FROM EntityLink WHERE
+               parent_entity_id = ? AND parent_entity_type = "rack" AND child_entity_type = "object"
+) x
+END;
+       $result = usePreparedSelectBlade ($query, array ($rack_id, $rack_id));
+       return $result->fetch (PDO::FETCH_COLUMN, 0);
+}
+
 // Used when sort order is manually changed, and when a rack is moved or deleted
 // Input is expected to be a pre-sorted array of rack IDs
 function updateRackSortOrder ($racks)
index 31ead8c..55db8f8 100644 (file)
@@ -616,6 +616,8 @@ function renderRackspaceRowEditor ()
                printOpFormIntro ('addRow');
                echo '<tr><td>';
                printImageHREF ('create', 'Add new row', TRUE);
+               echo '</td><td>&nbsp;';
+               echo '</td><td>&nbsp;';
                echo '</td><td><select name=location_id>';
                renderLocationSelectTree ();
                echo '</td><td><input type=text name=name></td><td>';
@@ -624,18 +626,21 @@ function renderRackspaceRowEditor ()
        }
        startPortlet ('Rows');
        echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
-       echo "<tr><th>&nbsp;</th><th>Location</th><th>Name</th><th>&nbsp;</th><th>Row link</th></tr>\n";
+       echo "<tr><th>&nbsp;</th><th># Racks</th><th># Devices</th><th>Location</th><th>Name</th><th>&nbsp;</th><th>Row link</th></tr>\n";
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
                printNewItemTR ();
        foreach (listCells ('row') as $row_id => $rowInfo)
        {
                echo '<tr><td>';
-               if ($rc = $rowInfo['rackc'])
-                       printImageHREF ('nodestroy', "${rc} rack(s) here");
-               else
-                       echo getOpLink (array('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row');
+               $rc = $rowInfo['rackc'];
+               $delete_racks_str = $rc ? " and $rc rack(s)" : '';
+               echo getOpLink (array ('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row'.$delete_racks_str, 'need-confirmation');
                printOpFormIntro ('updateRow', array ('row_id' => $row_id));
                echo '</td><td>';
+               echo $rc;
+               echo '</td><td>';
+               echo getRowMountsCount ($row_id);
+               echo '</td><td>';
                echo '<select name=location_id>';
                renderLocationSelectTree ($rowInfo['location_id']);
                echo "</td><td><input type=text name=name value='${rowInfo['name']}'></td><td>";
@@ -1220,12 +1225,18 @@ function renderEditRackForm ($rack_id)
        if ($rack['has_problems'] == 'yes')
                echo ' checked';
        echo "></td></tr>\n";
+       echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
        if ($rack['isDeletable'])
        {
-               echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
                echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation');
-               echo "&nbsp;</td></tr>\n";
+               echo "&nbsp;";
        }
+       else
+       {
+               echo getOpLink (array ('op'=>'cleanRack'), '' ,'clear', 'Reset (cleanup) rack mounts', 'need-confirmation');
+               echo "&nbsp;";
+       }
+       echo "</td></tr>\n";
        echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>";
        echo "<tr><td class=submit colspan=3>";
        printImageHREF ('SAVE', 'Save changes', TRUE);
@@ -1927,6 +1938,7 @@ function showMessageOrError ()
                49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
                51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
                57 => array ('code' => 'success', 'format' => 'Reset complete'),
+               58 => array ('code' => 'success', 'format' => '%u device(s) unmounted successfully'),
                63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
                67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
                71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
index 986c861..ab87205 100644 (file)
@@ -147,6 +147,7 @@ $ophandler['rack']['problems']['updateRack'] = 'updateRackProblems';
 $ophandler['rack']['edit']['clearSticker'] = 'clearSticker';
 $ophandler['rack']['edit']['updateRack'] = 'updateRack';
 $ophandler['rack']['edit']['deleteRack'] = 'deleteRack';
+$ophandler['rack']['edit']['cleanRack'] = 'cleanRack';
 $ophandler['rack']['log']['add'] = 'addObjectlog';
 $ophandler['rack']['log']['del'] = 'tableHandler';
 $ophandler['rack']['tags']['saveTags'] = 'saveEntityTags';
index 7634454..4c3d5e9 100644 (file)
@@ -2420,16 +2420,13 @@ function updateRow ()
 
 function deleteRow ()
 {
-       setFuncMessages (__FUNCTION__, array ('OK' => 7, 'ERR1' => 206));
-       assertUIntArg ('row_id');
-       $rowData = spotEntity ('row', $_REQUEST['row_id']);
-       amplifyCell ($rowData);
-       if (count ($rowData['racks']))
-       {
-               showFuncMessage (__FUNCTION__, 'ERR1', array ($rowData['name']));
-               return;
-       }
-       commitDeleteObject ($_REQUEST['row_id']);
+       setFuncMessages (__FUNCTION__, array ('OK' => 7, 'UMOUNT' => 58));
+       $row_id = assertUIntArg ('row_id');
+       $rowData = spotEntity ('row', $row_id);
+       $unmounted = getRowMountsCount ($row_id);
+       commitDeleteRow ($row_id);
+       if ($unmounted)
+               showFuncMessage (__FUNCTION__, 'UMOUNT', array ($unmounted));
        showFuncMessage (__FUNCTION__, 'OK', array ($rowData['name']));
        return buildRedirectURL ('rackspace', 'editrows');
 }
@@ -2524,20 +2521,25 @@ function deleteRack ()
        assertUIntArg ('rack_id');
        $rackData = spotEntity ('rack', $_REQUEST['rack_id']);
        amplifyCell ($rackData);
-       if (count ($rackData['mountedObjects']))
+       if (!$rackData['isDeletable'])
        {
                showFuncMessage (__FUNCTION__, 'ERR1');
                return;
        }
-       releaseFiles ('rack', $_REQUEST['rack_id']);
-       destroyTagsForEntity ('rack', $_REQUEST['rack_id']);
-       usePreparedDeleteBlade ('RackSpace', array ('rack_id' => $_REQUEST['rack_id']));
-       commitDeleteObject ($_REQUEST['rack_id']);
-       resetRackSortOrder ($rackData['row_id']);
+       commitDeleteRack ($_REQUEST['rack_id']);
        showFuncMessage (__FUNCTION__, 'OK', array ($rackData['name']));
        return buildRedirectURL ('rackspace', 'default');
 }
 
+function cleanRack ()
+{
+       setFuncMessages (__FUNCTION__, array ('OK' => 58));
+       $rack_id = assertUIntArg ('rack_id');
+       $unmounted = getRackMountsCount ($rack_id);
+       commitCleanRack ($rack_id);
+       showFuncMessage (__FUNCTION__, 'OK', array ($unmounted));
+}
+
 function updateRackDesign ()
 {
        $rackData = spotEntity ('rack', getBypassValue());