public function addChildAction()
 {
     $node_id = $this->getRequest("node_id", "");
     $node_whole = $this->getRequest("node_whole", "");
     $idc = $this->getRequest("idc", "");
     $sub_node = $this->getRequest("sub_node", "");
     $sub_node_val = $this->getRequest("sub_node_val", "");
     $main_buss_id = $this->getRequest("main_buss_id", "");
     $sub_buss_id = $this->getRequest("sub_buss_id", "");
     $note = $this->getRequest("note", "");
     $op_user = $this->userInfo["userName"];
     // 1. parameter is not right
     if ($node_id === "" || $node_whole === "" || $sub_node === "" || $idc === "" || $main_buss_id === "" || $sub_buss_id === "") {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_BAD_ARGS);
         QconfMgrLog::err(__FILE__, __LINE__, "parameter 'node_id' 'node_whole' 'idc' 'sub_node' " . "'main_buss_id' 'sub_buss_id' is null!");
         echo json_encode($res);
         return;
     }
     $sub_node = trim($sub_node, "/");
     // 2. check the path is not one level
     if (strpos($sub_node, "/") !== FALSE) {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_NODE_NAME_ERR);
         QconfMgrLog::err(__FILE__, __LINE__, "sub_node : {$sub_node} is not a one level node");
         echo json_encode($res);
         return;
     }
     // 3. check whether the node name has been used
     $ret = NodeServ::check($node_id, $sub_node);
     if ($ret === FALSE) {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_NODE_EXIST);
         QconfMgrLog::err(__FILE__, __LINE__, "node : {$node_id} already has a sub node named {$sub_node}");
         echo json_encode($res);
         return;
     }
     // 4. get the node info from database
     $dbnode = NodeServ::getNode($node_id);
     if ($dbnode === FALSE) {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_NODE_NOT_EXIST);
         QconfMgrLog::err(__FILE__, __LINE__, "node : {$node_id} is not exist!");
         echo json_encode($res);
         return;
     }
     $db_node_whole = $dbnode["node_whole"];
     if ($db_node_whole != $node_whole) {
         QconfMgrLog::err(__FILE__, __LINE__, "Inconsistent: node_id : {$node_id},\n                node_whole : {$node_whole} vs {$db_node_whole}");
     }
     //[USERPERM CHECK]
     $userperm_ret = UserPermServ::checkPerm($op_user, $db_node_whole);
     if ($userperm_ret === FALSE) {
         QconfMgrLog::err(__FILE__, __LINE__, "Insufficient permission of {$op_user} on node {$db_node_whole}");
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_USER_PERM_PERMISSION_DENIED);
         echo json_encode($res);
         return;
     }
     //[SNAPSHOT CHECK]
     $main_buss_id = $dbnode["main_buss_id"];
     $snapshot_ret = SnapShotUtil::existSnapShotForNode($main_buss_id, $db_node_whole, $snapshot_path);
     if ($snapshot_ret === FALSE) {
         QconfMgrLog::err(__FILE__, __LINE__, "snapshot operation failed");
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_SNAPSHOT_MODULE_FAILED);
         echo json_encode($res);
         return;
     }
     if ($snapshot_ret === InfoDescUtil::SNAPSHOT_FILE_EXIST) {
         QconfMgrLog::err(__FILE__, __LINE__, "snapshot existed on current node node_whole({$node_whole})");
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_SNAPSHOT_LOCKED_NODE);
         $res["errmsg"] .= ": {$snapshot_path}";
         echo json_encode($res);
         return;
     }
     $idc_list = preg_split("/[,]+/", $idc);
     // split by ,
     $idc_host = ZkConf::getZkHost($idc_list[0]);
     // 5. idc zookeeper server not exist
     if ($idc_host === NULL) {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_IDC_NOT_EXIST);
         echo json_encode($res);
         return;
     }
     $zk_web = new QconfZkWebBase(Log::INFO);
     $zk_web->connect($idc_host);
     $qconf_path = PathUtil::getQconfPathWithSubNode($db_node_whole, $sub_node);
     $ret = -1;
     $retry_time = 0;
     while ($ret === -1 && $retry_time <= InfoDescUtil::ZK_MAX_RETRY_TIME) {
         QconfMgrLog::err(__FILE__, __LINE__, "retry {$retry_time} of " . InfoDescUtil::ZK_MAX_RETRY_TIME . " to add conf: {$db_node_whole} on {$idc_host}");
         $ret = $zk_web->add_conf($qconf_path, $sub_node_val);
         $retry_time++;
     }
     // 6. zookeeper add failed
     if ($ret === -1) {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_ZOOKEEPER_FAIL);
         OpServ::insert(InfoDescUtil::OP_TYPE_ADD, $qconf_path, $idc, InfoDescUtil::OP_STATUS_ZOO_FAILED, $main_buss_id, $sub_buss_id, $op_user, "");
         echo json_encode($res);
         return;
     }
     $sub_path_whole = PathUtil::unionPath($db_node_whole, $sub_node);
     $ret = NodeServ::insert($node_id, $sub_node, InfoDescUtil::NODE_TYPE_NORMAL, $sub_path_whole, $main_buss_id, $sub_buss_id, $idc, $note);
     if ($ret === FALSE) {
         $res = InfoDescUtil::getErrorMsg(InfoDescUtil::ERR_MYSQL_FAIL);
         OpServ::insert(InfoDescUtil::OP_TYPE_ADD, $sub_path_whole, $idc, InfoDescUtil::OP_STATUS_MYSQL_FAILED, $main_buss_id, $sub_buss_id, $op_user, "");
         echo json_encode($res);
         return;
     }
     OpServ::insert(InfoDescUtil::OP_TYPE_ADD, $sub_path_whole, $idc, InfoDescUtil::OP_STATUS_SUCCESS, $main_buss_id, $sub_buss_id, $op_user, $sub_node_val);
     $res = array("errno" => "0", "errmsg" => "", "data" => "add child node success!");
     $json = json_encode($res);
     echo $json;
 }