소스 검색

AMBARI-446. Support Resume For Manage Services (Contributed by Varun)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/branches/ambari-186@1347284 13f79535-47bb-0310-9956-ffa450edef68
Vikram Dixit K 13 년 전
부모
커밋
3ad0124e40

+ 2 - 0
CHANGES.txt

@@ -5,6 +5,8 @@ should be listed by their full name. Please keep the file to a max of 80
 characters wide.
 
 Release 0.1.x - unreleased
+
+  AMBARI-446. Support Resume For Manage Services (Varun via Vikram)
   
   AMBARI-466. Add nodes page alerts removed in case of adding duplicate nodes (Vikram)
 

+ 2 - 1
hmc/html/manageServices.php

@@ -100,7 +100,8 @@
         '../js/utils.js',
         '../js/txnUtils.js',
         '../js/configureServicesUtils.js',
-        '../js/manageServices.js' 
+        '../js/manageServices.js',
+        '../js/manageServicesProgress.js'
       ];
     </script>
 

+ 45 - 0
hmc/html/showManageServicesProgress.php

@@ -0,0 +1,45 @@
+<?php require_once "./head.inc" ?>
+<html>
+  <head>
+    <title id="pageTitleId"><?php echo $RES['page.title'] ?></title>
+
+    <!-- CSS -->
+    <link type="text/css" rel="stylesheet" href="../yui-3.5.1/build/cssreset/cssreset-min.css">
+    <link type="text/css" rel="stylesheet" href="../css/bootstrap.css" media="screen"/>
+    <link type="text/css" rel="stylesheet" href="../css/common.css" media="screen"/>
+    <link type="text/css" rel="stylesheet" href="../css/common2.css" media="screen"/>
+    <link type="text/css" rel="stylesheet" href="../css/common3.css" media="screen"/>
+    <link rel="shortcut icon" href="../images/logo-micro.gif">
+    <!-- End CSS -->
+  </head>
+
+  <body class="yui3-skin-sam">
+    <?php require "./topnav.htmli"; ?>
+
+    <div id="contentDivId"> 
+
+      <?php require "./utils.htmli"; ?>
+      <?php require "./txnUtils.htmli"; ?>
+
+    </div>
+    <!-- End of contentDivId -->
+
+    <?php require "./footer.htmli"; ?>
+
+    <!-- Javascript Scaffolding -->
+    <script type="text/javascript">
+      /* Minimal data required to bootstrap clusters.js. */
+      var clusterName = '<?php echo $clusterName; ?>';
+
+      var jsFilesToLoad = [ 
+        '../js/utils.js',
+        '../js/txnUtils.js',
+        '../js/manageServicesProgress.js',
+        '../js/showManageServicesProgress.js' 
+      ];
+    </script>
+
+    <?php require "./bootstrapJs.htmli"; ?>
+    <!-- End of Javascript Scaffolding -->
+  </body>
+</html> 

+ 4 - 27
hmc/js/deployProgress.js

@@ -37,29 +37,6 @@ function generateLogsContent(errorInfoJson) {
 
 }
 
-function generateClustersListUrl( clusterName ) {
-
-  var url = '';
-
-  var currentUrl = window.location.href;
-  globalYui.log('Current URL: ' + currentUrl);
-  var currentPathPos = currentUrl.indexOf(window.location.pathname);
-  globalYui.log('Current Path Pos: ' + currentPathPos);
-
-  if( -1 != currentPathPos ) {
-
-    /*
-    url = currentUrl.substr(0, currentPathPos) + 
-      '/hmc/html/manageServices.php?clusterName=' + clusterName;
-  globalYui.log('Services Page URL: ' + url);
-      */
-    // ClusterName is no longer needed
-    url = currentUrl.substr(0, currentPathPos) + '/hmc/html/index.php';
-  }
-
-  return url;
-}
-
 function renderDeployProgress (deployProgressInfo) {
 
   hideLoadingImg();
@@ -115,7 +92,7 @@ function renderDeployProgress (deployProgressInfo) {
     success: function( txnProgressWidget ) {
 
       globalYui.one("#clustersListLinkId").on( "click", function(e) {
-        document.location.href = generateClustersListUrl(txnProgressWidget.txnProgressContext.clusterName);
+        document.location.href = generateHMCUrl();
       });
     },
 
@@ -174,10 +151,10 @@ function renderDeployProgress (deployProgressInfo) {
        * the contents inside errorInfoPanel (and make it visible). 
        */
       globalYui.one("#showDeployTxnLogsLinkId").on( "click", function(e) {
-        errorInfoPanel.set('centered', true);
-        errorInfoPanel.set('bodyContent', errorInfoPanelBodyContent );
-        errorInfoPanel.show();
 
+        errorInfoPanel.set( 'centered', true );
+        errorInfoPanel.set( 'bodyContent', errorInfoPanelBodyContent );
+        errorInfoPanel.show();
       });
     }
   };

+ 2 - 126
hmc/js/manageServices.js

@@ -349,131 +349,7 @@ function performServiceManagement( action, serviceName, confirmationDataPanel )
            */
           hideAndDestroyPanel();
 
-          var manageServicesProgressStatusMessage = {
-
-            success:
-              '<p>' +
-                'Successfully completed the operation. ' + 
-                  '<a href="javascript:void(null)" style="margin-left:10px;" id="closeManageServicesProgressWidgetLinkId">' + 
-                    'Continue' +
-                  '</a>' +
-              '</p>',
-
-            failure: 
-              '<p>' + 
-                'Failed to complete the operation.<br>Take a look at ' +
-                  '<a href="javascript:void(null)" id=showManageServicesTxnLogsLinkId>Operation Logs</a>' +
-                ' to see what might have gone wrong.' +
-                '<a href="javascript:void(null)" class="btn btn-large" style="margin:5px 0" id="closeManageServicesProgressWidgetLinkId">' + 
-                'Continue' +
-                '</a>' +
-              '</p>'
-          };
-
-          var manageServicesProgressPostCompletionFixup = {
-
-            success: function( txnProgressWidget ) {
-
-              /* Register a click-handler for the just-rendered 
-               * #closeManageServicesProgressWidgetLinkId.
-               *
-               * Don't worry about this being a double-registration - although
-               * it looks that way, it's not, because (an identical, but that's 
-               * irrelevant, really) manageServicesProgressStatusMessage.success 
-               * is re-rendered afresh each time through, and thus this 
-               * click-handler must also be re-registered each time 'round.
-               */
-              globalYui.one("#closeManageServicesProgressWidgetLinkId").on( "click", function(e) {
-                txnProgressWidget.hide();
-              });
-
-              /* Resume polling for information about the cluster's services. */
-              fetchClusterServicesPoller.start();
-            },
-
-            failure: function( txnProgressWidget ) {
-              
-              globalYui.one("#closeManageServicesProgressWidgetLinkId").on( "click", function(e) {
-                txnProgressWidget.hide();
-              });
-
-              
-              /* <-------------------- REZXXX BEGIN -----------------------> */
-
-              /* Create the panel that'll display our error info. */
-              var errorInfoPanel = 
-                createInformationalPanel( '#informationalPanelContainerDivId', 'Operation Logs' );
-
-              /* Prime the panel to start off showing our stock loading image. */
-              var errorInfoPanelBodyContent = 
-                '<img id=errorInfoPanelLoadingImgId class=loadingImg src=../images/loading.gif />';
-
-              /* Make the call to our backend to fetch the report for this txnId. */
-              globalYui.io('../php/frontend/fetchTxnLogs.php?clusterName=' + 
-                txnProgressWidget.txnProgressContext.clusterName + '&txnId=' + txnProgressWidget.txnProgressContext.txnId, {
-                  
-                timeout: 10000,
-                on: {
-                  success: function (x,o) {
-
-                    globalYui.log("RAW JSON DATA: " + o.responseText);
-
-                    var errorInfoJson = null;
-
-                    // Process the JSON data returned from the server
-                    try {
-                      errorInfoJson = globalYui.JSON.parse(o.responseText);
-                    }
-                    catch (e) {
-                      alert("JSON Parse failed!");
-                      return;
-                    }
-
-                    /* TODO XXX Remove some of the noise from this to allow
-                     * for better corelation - for now, just dump a 
-                     * pretty-printed version of the returned JSON.
-                     */
-                    errorInfoPanelBodyContent = 
-                      '<pre>' + 
-                        globalYui.JSON.stringify( errorInfoJson.logs, null, 4 ) +
-                      '</pre>';
-
-                    /* Update the contents of errorInfoPanel (which was, till
-                     * now, showing the loading image). 
-                     */
-                    errorInfoPanel.set( 'bodyContent', errorInfoPanelBodyContent );
-                  },
-                  failure: function (x,o) {
-                    alert("Async call failed!");
-                  }
-                }
-              });
-
-              var firstTimeShowingErrorInfoPanel = true;
-
-              /* Register a click-handler for #showManageServicesTxnLogsLinkId 
-               * to render the contents inside errorInfoPanel (and make it visible). 
-               */
-              globalYui.one("#showManageServicesTxnLogsLinkId").on( "click", function(e) {
-
-                errorInfoPanel.set( 'bodyContent', errorInfoPanelBodyContent );
-                errorInfoPanel.show();
-
-              });
-
-              /* <--------------------- REZXXX END ------------------------> */
-
-              /* Resume polling for information about the cluster's services. */
-              /* TODO XXX Move this into the click handler for closing the widget after the first show of the panel... */
-              fetchClusterServicesPoller.start();
-            }
-          };
-
-          var manageServicesProgressWidget = new TxnProgressWidget
-            ( manageServicesResponseJson, 'Performing Service Operation', manageServicesProgressStatusMessage, manageServicesProgressPostCompletionFixup );
-
-          /* And now that confirmationDataPanel is hidden, show manageServicesProgressWidget. */
-          manageServicesProgressWidget.show();
+          renderManageServicesProgress( manageServicesResponseJson.response );
         }
         else {
           /* No need to hide confirmationDataPanel here - there are errors 
@@ -487,7 +363,7 @@ function performServiceManagement( action, serviceName, confirmationDataPanel )
                 handleConfigureServiceErrors( manageServicesResponseJson );
             });
           });
-        } else {
+          } else {
             // Can't do anything for others
             alert('Got error during ' + action + ' : ' + globalYui.Lang.dump(manageServicesResponseJson));
           }

+ 149 - 0
hmc/js/manageServicesProgress.js

@@ -0,0 +1,149 @@
+function renderManageServicesProgress( manageServicesProgressInfo ) {
+
+  var manageServicesProgressStatusMessage = {
+
+    success:
+      '<p>' +
+        'Successfully completed the operation. ' + 
+          '<a href="javascript:void(null)" id=closeManageServicesProgressWidgetLinkId>' + 
+            'Continue' +
+          '</a>' +
+      '</p>',
+
+    failure: 
+      '<p>' + 
+        'Failed to complete the operation.  Please ' +
+          '<a href="javascript:void(null)" id=showManageServicesTxnLogsLinkId>take a look at Operation Logs</a>' +
+        ' to see what might have gone wrong.' +
+      '</p>'
+  };
+
+  var manageServicesProgressPostCompletionFixup = {
+
+    success: function( txnProgressWidget ) {
+
+      /* Register a click-handler for the just-rendered 
+       * #closeManageServicesProgressWidgetLinkId.
+       *
+       * Don't worry about this being a double-registration - although
+       * it looks that way, it's not, because (an identical, but that's 
+       * irrelevant, really) manageServicesProgressStatusMessage.success 
+       * is re-rendered afresh each time through, and thus this 
+       * click-handler must also be re-registered each time 'round.
+       */
+      globalYui.one("#closeManageServicesProgressWidgetLinkId").on( "click", function(e) {
+
+        var manageServicesUriPath = '/hmc/html/manageServices.php';
+        var manageServicesUriPathRegEx = new RegExp(manageServicesUriPath);
+
+        /* If we're already on manageServicesUriPath, just close the txnProgressWidget. */
+        if( window.location.pathname.match(manageServicesUriPathRegEx) ) {
+          txnProgressWidget.hide();
+        }
+        /* If not, redirect to manageServicesUriPath. */
+        else {
+          document.location.href = generateHMCUrl
+            ( manageServicesUriPath + '?clusterName=' + txnProgressWidget.txnProgressContext.clusterName );
+        }
+      });
+
+      /* Resume polling for information about the cluster's services. */
+      if( typeof fetchClusterServicesPoller != 'undefined' ) {
+        fetchClusterServicesPoller.start();
+      }
+    },
+
+    failure: function( txnProgressWidget ) {
+
+      /* <-------------------- REZXXX BEGIN -----------------------> */
+
+      /* Create the panel that'll display our error info. */
+      var errorInfoPanel = 
+        createInformationalPanel( '#informationalPanelContainerDivId', 'Operation Logs' );
+
+      /* Prime the panel to start off showing our stock loading image. */
+      var errorInfoPanelBodyContent = 
+        '<img id=errorInfoPanelLoadingImgId class=loadingImg src=../images/loading.gif />';
+
+      /* Make the call to our backend to fetch the report for this txnId. */
+      globalYui.io('../php/frontend/fetchTxnLogs.php?clusterName=' + 
+        txnProgressWidget.txnProgressContext.clusterName + '&txnId=' + txnProgressWidget.txnProgressContext.txnId, {
+          
+        timeout: 10000,
+        on: {
+          success: function (x,o) {
+
+            globalYui.log("RAW JSON DATA: " + o.responseText);
+
+            var errorInfoJson = null;
+
+            // Process the JSON data returned from the server
+            try {
+              errorInfoJson = globalYui.JSON.parse(o.responseText);
+            }
+            catch (e) {
+              alert("JSON Parse failed!");
+              return;
+            }
+
+            /* TODO XXX Remove some of the noise from this to allow
+             * for better corelation - for now, just dump a 
+             * pretty-printed version of the returned JSON.
+             */
+            errorInfoPanelBodyContent = 
+              '<pre>' + 
+                globalYui.JSON.stringify( errorInfoJson.logs, null, 4 ) +
+              '</pre>';
+
+            /* Update the contents of errorInfoPanel (which was, till
+             * now, showing the loading image). 
+             */
+            errorInfoPanel.set( 'bodyContent', errorInfoPanelBodyContent );
+          },
+          failure: function (x,o) {
+            alert("Async call failed!");
+          }
+        }
+      });
+
+      var firstTimeShowingErrorInfoPanel = true;
+
+      /* Register a click-handler for #showManageServicesTxnLogsLinkId 
+       * to render the contents inside errorInfoPanel (and make it visible). 
+       */
+      globalYui.one("#showManageServicesTxnLogsLinkId").on( "click", function(e) {
+
+        errorInfoPanel.set( 'centered', true );
+        errorInfoPanel.set( 'bodyContent', errorInfoPanelBodyContent );
+        errorInfoPanel.show();
+
+        if( firstTimeShowingErrorInfoPanel ) {
+
+          globalYui.one('#txnProgressStatusActionsDivId').setContent(  
+            '<a href="javascript:void(null)" id=closeManageServicesProgressWidgetLinkId>' + 
+              'Close' +
+            '</a>' );
+
+          globalYui.one("#closeManageServicesProgressWidgetLinkId").on( "click", function(e) {
+
+            txnProgressWidget.hide();
+          });
+
+          firstTimeShowingErrorInfoPanel = false;
+        }
+      });
+
+      /* <--------------------- REZXXX END ------------------------> */
+
+      if( typeof fetchClusterServicesPoller != 'undefined' ) {
+        /* Resume polling for information about the cluster's services. */
+        fetchClusterServicesPoller.start();
+      }
+    }
+  };
+
+  var manageServicesProgressWidget = new TxnProgressWidget
+    ( manageServicesProgressInfo, 'Manage Services', manageServicesProgressStatusMessage, manageServicesProgressPostCompletionFixup );
+
+  manageServicesProgressWidget.show();
+}

+ 2 - 0
hmc/js/showManageServicesProgress.js

@@ -0,0 +1,2 @@
+/* Main() */
+executeStage( '../php/frontend/manageServices.php?clusterName=' + clusterName, renderManageServicesProgress );

+ 2 - 25
hmc/js/uninstallProgress.js

@@ -37,29 +37,6 @@ function generateLogsContent(errorInfoJson) {
 
 }
 
-function generateClustersListUrl( clusterName ) {
-
-  var url = '';
-
-  var currentUrl = window.location.href;
-  globalYui.log('Current URL: ' + currentUrl);
-  var currentPathPos = currentUrl.indexOf(window.location.pathname);
-  globalYui.log('Current Path Pos: ' + currentPathPos);
-
-  if( -1 != currentPathPos ) {
-
-    /*
-    url = currentUrl.substr(0, currentPathPos) + 
-      '/hmc/html/manageServices.php?clusterName=' + clusterName;
-  globalYui.log('Services Page URL: ' + url);
-      */
-    // ClusterName is no longer needed
-    url = currentUrl.substr(0, currentPathPos) + '/hmc/html/index.php';
-  }
-
-  return url;
-}
-
 function renderUninstallProgress (uninstallProgressInfo) {
 
   hideLoadingImg();
@@ -90,14 +67,14 @@ function renderUninstallProgress (uninstallProgressInfo) {
     success: function( txnProgressWidget ) {
 
       globalYui.one("#clustersListLinkId").on( "click", function(e) {
-        document.location.href = generateClustersListUrl(txnProgressWidget.txnProgressContext.clusterName);
+        document.location.href = generateHMCUrl();
       });
     },
 
     failure: function( txnProgressWidget ) {
 
       globalYui.one("#clustersListLinkId").on( "click", function(e) {
-        document.location.href = generateClustersListUrl(txnProgressWidget.txnProgressContext.clusterName);
+        document.location.href = generateHMCUrl();
       });
       
       /* Create the panel that'll display our error info. */

+ 18 - 0
hmc/js/utils.js

@@ -461,3 +461,21 @@ function titleCase(word){
   return word.substr(0,1).toUpperCase() + word.substr(1).toLowerCase();
 }
 
+function generateHMCUrl( uriPath ) {
+
+  var url = '';
+
+  /* By default, go to the HMC home page. */
+  uriPath = ( typeof uriPath == "undefined" ) ? '/hmc/html/index.php' : uriPath;
+    
+  var currentUrl = window.location.href;
+  globalYui.log('Current URL: ' + currentUrl);
+  var currentPathPos = currentUrl.indexOf(window.location.pathname);
+  globalYui.log('Current Path Pos: ' + currentPathPos);
+
+  if( -1 != currentPathPos ) {
+    url = currentUrl.substr(0, currentPathPos) + uriPath;
+  }
+
+  return url;
+}

+ 0 - 8
hmc/php/frontend/deployPostProcess.php

@@ -19,14 +19,6 @@ function deployPostProcess($clusterName, $user, $txnId, $progress)
   $result = 0;
   $error = "";
 
-  $txnStatusInfo = $dbAccessor->getTransactionStatusInfo($clusterName, $txnId);
-  if ($txnStatusInfo['result'] != 0) {
-    $logger->log_error("Deploy post process get txn info failed");
-    $result = $txnStatusInfo['result'];
-    $error = $txnStatusInfo['error'];
-    return (array("result" => $result, "error" => $error));
-  }
-
   $txnStatus = !($progress['encounteredError']);
   $state = "DEPLOYED";
   if ($txnStatus) {

+ 19 - 3
hmc/php/frontend/fetchTxnProgress.php

@@ -6,6 +6,8 @@ include_once "../orchestrator/HMC.php";
 include_once '../util/clusterState.php';
 include_once "uninstallCleanup.php";
 include_once "deployPostProcess.php";
+include_once "uninstallCleanup.php";
+include_once "manageServicesPostProcess.php";
 
 $dbPath = $GLOBALS["DB_PATH"];
 
@@ -16,12 +18,26 @@ $deployUser = $_GET['deployUser'];
 $logger = new HMCLogger("TxnProgress");
 
 $map = array(
+  "HMC::deployHDP" => array (
+      "deployPostProcess"
+  ),
   "HMC::uninstallHDP" => array (
       "deBootStrap"
   ),
-
-  "HMC::deployHDP" => array (
-      "deployPostProcess"
+  "HMC::startAllServices" => array (
+      "manageServicesPostProcess"
+  ),
+  "HMC::stopAllServices" => array (
+      "manageServicesPostProcess"
+  ),
+  "HMC::startServices" => array (
+      "manageServicesPostProcess"
+  ),
+  "HMC::stopServices" => array (
+      "manageServicesPostProcess"
+  ),
+  "HMC::reconfigureServices" => array (
+      "manageServicesPostProcess"
   )
 );
 

+ 95 - 60
hmc/php/frontend/manageServices.php

@@ -14,13 +14,7 @@ include_once "../puppet/DBReader.php";
 include_once "../puppet/PuppetInvoker.php";
 include_once "configUtils.php";
 include_once '../util/suggestProperties.php';
-
-$logger = new HMCLogger("ManageServices");
-$dbPath = $GLOBALS["DB_PATH"];
-$clusterName = $_GET['clusterName'];
-$dbAccessor = new HMCDBAccessor($dbPath);
-
-header("Content-type: application/json");
+include_once "../util/clusterState.php";
 
 function performServiceManagement( $hmc, $requestObj )
 {
@@ -29,7 +23,7 @@ function performServiceManagement( $hmc, $requestObj )
   global $clusterName;
 
   /* What we're here to return. */
-  $result = array();
+  $serviceManagementResult = array();
 
   $action = $requestObj['action'];
 
@@ -38,22 +32,22 @@ function performServiceManagement( $hmc, $requestObj )
   switch( $action )
   {
     case 'startAll':
-      $result = $hmc->startAllServices();
+      $serviceManagementResult = $hmc->startAllServices();
       break;
 
     case 'stopAll':
-      $result = $hmc->stopAllServices();
+      $serviceManagementResult = $hmc->stopAllServices();
       break;
 
     case 'start':
       if( count($serviceNames) > 0 ) {
-        $result = $hmc->startServices( $serviceNames );
+        $serviceManagementResult = $hmc->startServices( $serviceNames );
       }
       break;
 
     case 'stop':
       if( count($serviceNames) > 0 ) {
-        $result = $hmc->stopServices( $serviceNames );
+        $serviceManagementResult = $hmc->stopServices( $serviceNames );
       }
       break;
 
@@ -63,77 +57,118 @@ function performServiceManagement( $hmc, $requestObj )
 
         /* Read additional data from $requestObj and update the DB
          * accordingly before attempting to call $hmc->reconfigureServices().
-         *
          */
-
-        /*
-        $configsToUpdate = array ();
-        foreach ($requestObj['services'] as $svcName => $svcInfo) {
-          if (!isset($svcInfo["properties"])
-              || !is_array($svcInfo["properties"])) {
-            continue;
-          }
-          // TODO: Stupid translation, FIXME says tshooter to hitman
-          $finalProperties = array();
-          foreach ($svcInfo["properties"] as $key => $valueObj) {
-            $finalProperties[$key] = $valueObj["value"];
-          }
-          $configsToUpdate = array_merge($configsToUpdate, $finalProperties);
-        }
-        $result = $dbAccessor->updateServiceConfigs($clusterName, $configsToUpdate);
-        if ($result['result'] != 0) {
-          $logger->log_error("Failed to update the configs in DB, error=" . $result["error"]);
-          return $result;
-        }
-        */
-
         // re-using persistConfigs code
-        $result = validateAndPersistConfigsFromUser($dbAccessor, $logger, $clusterName, $requestObj['services']);
-        if ($result['result'] != 0) {
-          $logger->log_error("Failed to validate configs from user, error=" . $result["error"]);
-          return $result;
+        $serviceManagementResult = validateAndPersistConfigsFromUser($dbAccessor, $logger, $clusterName, $requestObj['services']);
+        if ($serviceManagementResult['result'] != 0) {
+          $logger->log_error("Failed to validate configs from user, error=" . $serviceManagementResult["error"]);
+          return $serviceManagementResult;
         }
 
-        /*
-         * Also, remember to save a snapshot of the outgoing service
-         * config in the 'ConfigHistory' table (thanks, @tshooter).
+        /* Also, remember to save a snapshot of the outgoing service
+         * config in the 'ConfigHistory' table.
          */
         $changeMsg = "Reconfiguring services, list=" . implode(",", $serviceNames);
-        $result = $dbAccessor->createServiceConfigSnapshot($clusterName, $changeMsg);
-        if ($result['result'] != 0) {
-          $logger->log_error("Failed to create config snapshot in DB, error=" . $result["error"]);
-          return $result;
+        $serviceManagementResult = $dbAccessor->createServiceConfigSnapshot($clusterName, $changeMsg);
+        if ($serviceManagementResult['result'] != 0) {
+          $logger->log_error("Failed to create config snapshot in DB, error=" . $serviceManagementResult["error"]);
+          return $serviceManagementResult;
         }
 
-        $result = $hmc->reconfigureServices( $serviceNames );
+        $serviceManagementResult = $hmc->reconfigureServices( $serviceNames );
       }
       break;
 
     default:
       $logger->log_error( "Unrecognized action '" . $action . "' requested" );
-      $result = array ( "result" => -1 , "error" => "Invalid action, action=" . $action);
+      $serviceManagementResult = array ( "result" => -1 , "error" => "Invalid action, action=" . $action);
       break;
   }
 
-  return $result;
+  return $serviceManagementResult;
 }
 
-$hmc = new HMC($dbPath, $clusterName);
+$dbPath = $GLOBALS["DB_PATH"];
+$clusterName = $_GET['clusterName'];
+
+/* For returning in our JSON at the very end. */
+$result = 0;
+$error = "";
 
-/* Slurp in the POST body. */
-$requestData = file_get_contents('php://input');
-$requestObj = json_decode($requestData, true);
+$txnId = -1;
 
-/* The Main Event. */
-$result = performServiceManagement($hmc, $requestObj);
+$logger = new HMCLogger("ManageServices");
 
-/* Augment $result with 'clusterName'. */
-$result["clusterName"] = $clusterName;
+$dbAccessor = new HMCDBAccessor($dbPath);
+$clusterStateResponse = $dbAccessor->getClusterState($clusterName);
 
-if ($result["result"] != 0 ) {
-  $logger->log_error("Failed to take an action in manage services, error=" . $result["error"]);
+if ($clusterStateResponse['result'] != 0) {
+  print json_encode($clusterStateResponse);
+  return;
 }
 
-print (json_encode($result));
+$clusterState = json_decode($clusterStateResponse['state'], true);
+
+/* Perform the actual management only if this cluster is in a deployed state 
+ * (regardless of whether the deploy was a success or failure). 
+ */
+if ($clusterState['state'] == 'DEPLOYED') {
+
+  $hmc = new HMC($dbPath, $clusterName);
+
+  /* Slurp in the POST body. */
+  $requestData = file_get_contents('php://input');
+  $requestObj = json_decode($requestData, true);
+
+  /* The Main Event. */
+  $serviceManagementResult = performServiceManagement($hmc, $requestObj);
+
+  if ($serviceManagementResult["result"] != 0 ) {
+    $logger->log_error("Failed to take an action in manage services, error=" . $serviceManagementResult["error"]);
+    print json_encode($serviceManagementResult);
+    return;
+  }
+
+  $txnId = $serviceManagementResult["txnId"];
+
+  /* (And when we kick off the management action is the only time to update the 
+   * state of the cluster). 
+   */
+  $state = "SERVICE_MANAGEMENT_IN_PROGRESS";
+  $displayName = "Service management in progress";
+  $context = array (
+    'txnId' => $txnId,
+    /* We've come here only if the cluster is in the "DEPLOYED" state, so the 
+     * state we stash is the state at the end of the deploy - we'll restore 
+     * this state at the end of the service management action.
+     */
+    'stashedDeployState' => $clusterState
+  );
+
+  $retval = updateClusterState($clusterName, $state, $displayName, $context);
+  if ($retval['result'] != 0) {
+    $result = $retval['result'];
+    $error = $retval['error'];
+  }
+}
+/* In case a management operation is already running, just return the txnId 
+ * from the DB instead of kicking off a fresh managemen action - this is so 
+ * we can try and preclude multiple managements occurring in parallel.
+ */
+elseif ($clusterState['state'] == 'SERVICE_MANAGEMENT_IN_PROGRESS') {
+
+  $txnId = $clusterState['context']['txnId'];
+}
+
+/* Create the output data... */
+$jsonOutput = array(
+    'clusterName' => $clusterName,
+    'txnId' => $txnId
+  );
+
+/* ...and spit it out. */
+header("Content-type: application/json");
+
+print (json_encode(array("result" => $result, "error" => $error, "response" => $jsonOutput)));
 
 ?>

+ 59 - 0
hmc/php/frontend/manageServicesPostProcess.php

@@ -0,0 +1,59 @@
+<?php
+
+include_once '../util/Logger.php';
+include_once '../conf/Config.inc';
+include_once 'localDirs.php';
+include_once "../util/lock.php";
+include_once '../db/HMCDBAccessor.php';
+include_once '../util/clusterState.php';
+
+include_once 'commandUtils.php';
+include_once "../util/HMCTxnUtils.php";
+
+function manageServicesPostProcess($clusterName, $user, $txnId, $progress)
+{
+  $logger = new HMCLogger("ManageServicesPostProcess");
+  $dbAccessor = new HMCDBAccessor($GLOBALS["DB_PATH"]);
+
+  $result = 0;
+  $error = "";
+
+  /* Safe fallbacks, in case the call to getClusterState() below fails. */
+  $state = "DEPLOYED";
+  $displayName = "Deployed successfully";
+  $context = array (
+    'status' => TRUE
+  );
+
+  $clusterStateResponse = $dbAccessor->getClusterState($clusterName);
+
+  if ($clusterStateResponse['result'] != 0) {
+    $logger->log_error("Failed to fetch cluster state (for restoration of stashed state)");
+
+    $result = $clusterStateResponse["result"];
+    $error = $clusterStateResponse["error"];
+  }
+  else {
+    $clusterState = json_decode($clusterStateResponse['state'], true);
+
+    $stashedDeployState = $clusterState["context"]["stashedDeployState"]; 
+    /* Restore the cluster's state to that stashed at the time of beginning the
+     * service management. 
+     */
+    $state = $stashedDeployState["state"];
+    $displayName = $stashedDeployState["displayName"];
+    $context = $stashedDeployState["context"];
+  }
+
+  // update state of the cluster 
+  $retval = updateClusterState($clusterName, $state, $displayName, $context);
+  if ($retval['result'] != 0) {
+    $logger->log_error("Update cluster state failed");
+    $result = $retval['result'];
+    $error = $retval['error'];
+  }
+
+  return (array("result" => $result, "error" => $error));
+}
+
+?>