实现真实的机柜模拟图[原创]


一般能反映机房设备位置、结构我们都喜欢通过网络拓扑图来展现,但个人感觉还不够直观、明了的表现出自己想要的结果(自己太挑剔了,呵呵)。因此写一个生成真实机柜模拟图平台,实现与真实服务器外观、服务状态、空闲位置等信息。
在线效果图
http://blog.liuts.com/idc/
系统截图
1、平台显示某一排截图
1.png
2、平台显示某台服务器详细信息截图
2.png
3、状态说明
3.gif
2U服务器正常状态
4.gif
2U服务器当机状态

系统原理
       通过获取运维平台的服务器信息(包括位置、操作系统、机型等),格式为XML,通过c++的tinyxml来解析并渲染成比较美观的HTML格式。当机的信息通过Nagios来获取。这样就可以生成非常人性化的展现平台了:)

系统代码Servermap.cpp

view plainprint?
/*************************************************************************** 
 *   Copyright (C) 2010 by Liu Tiansi   * 
 *   liutiansi@gmail.com   * 
 *                                                                         * 
 *   This program is free software; you can redistribute it and/or modify  * 
 *   it under the terms of the GNU General Public License as published by  * 
 *   the Free Software Foundation; either version 2 of the License, or     * 
 *   (at your option) any later version.                                   * 
 *                                                                         * 
 *   This program is distributed in the hope that it will be useful,       * 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * 
 *   GNU General Public License for more details.                          * 
 *                                                                         * 
 *   You should have received a copy of the GNU General Public License     * 
 *   along with this program; if not, write to the                         * 
 *   Free Software Foundation, Inc.,                                       * 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, CN.             * 
 ***************************************************************************/  
  
  
#include <iostream>  
#include <vector>  
#include <string>  
#include <fstream>  
#include "tinyxml.h"  
#include "tinyxml.cpp"  
#include "tinystr.h"  
#include "tinystr.cpp"  
#include "tinyxmlparser.cpp"  
#include "tinyxmlerror.cpp"  
  
using namespace std;  
  
class servermap {  
  
  public:  
    servermap( string *serverrow,string _idctype);  
    ~servermap();  
    string int2str( int num);  
    void Getdownserver ();  
    string writefile (string filename);  
    string GetServerCondition (string ip,string servertype);  
    string (*displayXmlDocument_info (string filename))[5];  
    void ProduRow();  
    void ProduCurrServer();  
  
  private:  
    string idctype;  
    string (*p_info)[5];  // 所有的服务器信息指针(从XML文件中遍历);  
    string (*pserver_info)[5];  // 当前机房的服务器信息指针(从XML文件中遍历);  
    string ServerInfo[800][5];  // 所有的服务器信息数组(从XML文件中遍历);  
    string ServerInfo_CurrServer[300][5];  //当前机房数组,从ServerInfo中过滤出来;  
    string ServerDownIP[50];    //当服务器清单;  
    int ServerInfoNumber;  //获取所有信息的有效行;  
    string *CurrServer_row;  //指向当前机房数组的指针;  
    int CurrServerInfoNumber;  //获取当前机房信息的有效行;  
    string HTMLstr;    //存储HTML串;  
};  
  
//构造func,传入排数及机房类型;  
servermap::servermap( string *Serverrow,string _idctype)  
{  
  idctype=_idctype;  
  //初始化HTML头;  
  HTMLstr="<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"  content=\"5\">\n<title>服务器模拟状态图</title>\n";  
  HTMLstr+="<script src='/js/server_top.js' language='javascript'></script>\n";  
    
  //机房排数组;  
  CurrServer_row=Serverrow;  
  ServerInfoNumber=0;  
  CurrServerInfoNumber=0;  
  
  //获取当前服务器清单;  
  Getdownserver();  
  
  //遍历所有服务器信息;  
  displayXmlDocument_info("ServerInfoAll.xml");  
  
  //简化当前机房服务器清单;  
  ProduCurrServer();  
}  
  
//类虚构func,销毁创建的指针;  
servermap::~servermap()  
{  
  //clear mem;  
}  
  
//整形转字符串方法;  
 string servermap::int2str( int num)  
{  
    if (num == 0 )  
       return " 0 ";  
    string str = "" ;  
    int num_ = num > 0 ? num : - 1 * num;  
  
    while (num_)  
    {  
       str = ( char )(num_ % 10 + 48 ) + str;  
       num_ /= 10 ;  
    }  
  
    if (num < 0 )  
       str = " - " + str;  
    return str;  
}  
  
//返回服务器状态图片;  
string servermap::GetServerCondition (string ip,string servertype)  
{  
  bool Obtaining=false;  
  for (int i=0;i<50;i++)  
  {  
    if (ServerDownIP[i]==ip)  
    {  
      Obtaining=true;  
      break;  
    }  
  }  
  
  if (servertype=="1U")  
  if (Obtaining)  
    return "1u_down.gif";  
  else return "1u_normal.gif";  
  
  if (servertype=="2U")  
  if (Obtaining)  
    return "2u_down.gif";  
  else return "2u_normal.gif";  
  
  if (servertype=="6U")  
  if (Obtaining)  
    return "ta_down.gif";  
  else return "ta_normal.gif";  
}  
  
//获取当机服务器清单,从文件中获取;  
void servermap::Getdownserver()  
{  
  string mainpath="/ServerDownlist";  
  string ip;  
  ifstream FileObject;  
  FileObject.open(mainpath.c_str(),ios::in);  
  int i=0;  
      while(getline(FileObject,ip))  
      {  
    ServerDownIP[i]=ip;  
    i+=1;  
  }  
     FileObject.close();  
}  
  
//写配置文件方法,形参为文件名;  
string servermap::writefile(string filename)  
{  
  string mainpath="/www/webroot/"+filename;  
  ofstream FileObject;  
  FileObject.open(mainpath.c_str(),ios::out);  
  FileObject<<HTMLstr<<endl;  
     FileObject.close();  
  return "1";  
}  
  
  
//获取XML文件服务器信息数据到指针;  
string (* servermap::displayXmlDocument_info(string filename))[5]  
{  
  TiXmlDocument doc(filename.c_str());  
  doc.LoadFile();  
  TiXmlElement *root_r = doc.RootElement();  
  //static vector<vector<string> > ClassInfo(m,vector<string>(n));  
  int i=0;  
  for(TiXmlNode *node = root_r->FirstChild(); node; node = node->NextSibling())  
  {  
    //输出元素节点名称;  
    //cout << node->Value() << endl;  
  
    //遍历输出节点属性名称及值;  
    if (node->Type() == TiXmlNode::ELEMENT)  
    {  
      for(TiXmlAttribute *attr = node->ToElement()->FirstAttribute(); attr; attr = attr->Next())  
      {  
        cout << "    " << attr->Name() << " =: " << attr->Value() << endl;  
      }  
    }  
    //遍历输出子节点名称及值;  
    TiXmlNode *child = node->FirstChild();  
    int j=0;  
    while(child)  
    {  
      int type = child->Type();  
      if (type == TiXmlNode::ELEMENT)  
      {  
        ServerInfo[i][j]=child->ToElement()->GetText();  
      }  
      child = node->IterateChildren(child);  
      j+=1;  
    }  
    i+=1;  
  
  }  
  ServerInfoNumber=i;  
  p_info=ServerInfo;  
  //free(ClassInfo);  
}  
  
//生成当前机房数组;  
void servermap::ProduCurrServer()  
{  
  const char * strtmp;  
  string strswap,stradd,Position0,Position1,Position2,Position3;  
  
  for (int i=0;i<10;i++)  
  {  
    if (CurrServer_row[i]=="")  
      break;  
    for (int j=0;j<ServerInfoNumber;j++)  
    {  
      strswap=*(*(p_info+j)+3);  
      strtmp=strswap.c_str();  
      Position0=strtmp[0];  
      Position1=strtmp[1];  
      Position2=strtmp[2];  
      Position3=strtmp[3];  
      if (idctype=="idc")  
        stradd=Position0+Position1;  
      else  
        stradd=Position0+Position1+Position2+Position3;  
      if (stradd==CurrServer_row[i])  
      {  
        CurrServerInfoNumber+=1;  
        ServerInfo_CurrServer[CurrServerInfoNumber][0]=*(*(p_info+j)+0);  
        ServerInfo_CurrServer[CurrServerInfoNumber][1]=*(*(p_info+j)+1);  
        ServerInfo_CurrServer[CurrServerInfoNumber][2]=*(*(p_info+j)+2);  
        ServerInfo_CurrServer[CurrServerInfoNumber][3]=*(*(p_info+j)+3);  
        ServerInfo_CurrServer[CurrServerInfoNumber][4]=*(*(p_info+j)+4);  
      }  
    }  
  }  
  pserver_info=ServerInfo_CurrServer;  
}  
  
//生成服务器拓扑状态图;  
void servermap::ProduRow()  
{  
  string point_moddle_key="-0";  
  string point_moddle="";  
  string point_last="";  
  string point_all="";  
  string substrServer="";  
  string DIVstr="";  
  int allservercount=0;  
  //所有机柜循环体;  
  for (int i=0;i<10;i++)  
  {  
    if (CurrServer_row[i]=="")  
      break;  
  
    //当前排循环体;  
    if (idctype=="idc")  
      HTMLstr+="<div align=center>"+CurrServer_row[i].substr(0,2)+"排</div>\n";  
    else  
      HTMLstr+="<div align=center>"+CurrServer_row[i].substr(2,2)+"排</div>\n";  
    HTMLstr+="<table width='1024' border='0' cellpadding='1' cellspacing='3' bgcolor='#ffffff' class='jjtable'>\n";  
          HTMLstr+="<tr align='center' valign='top'>\n";  
  
    for (int j=1;j<=7;j++)  
    {  
      point_moddle=point_moddle_key+int2str(j);  
              HTMLstr+="<td width='147' bgcolor='#eeeeee' background=\"/images/serverico/jg.gif\" >\n";  
      //HTMLstr+="<td width='147' style=\"BACKGROUND: url(/images/serverico/jg.gif) #edf6fb repeat-y 0px 0px;\">\n"  ;  
      HTMLstr+="<table width='99%' height='440'  border='0' cellpadding='1' cellspacing='0'>\n";  
            HTMLstr+="<tr>\n";  
              HTMLstr+="  <td height='30' align='center' valign='bottom'  class='jgtable'><font class=jgtitle>0"+int2str(j)+"</font></td></tr>\n";  
  
      //当前列循环体;  
      for (int k=1;k<=10;k++)  
      {  
        if (k==10)  
          point_last="-10";  
        else  
          point_last=point_moddle_key+int2str(k);  
        point_all=CurrServer_row[i]+point_moddle+point_last;  
  
        HTMLstr+="<tr>\n";  
        HTMLstr+="  <td height='30' align='center' valign='bottom' class='jgtable'>\n";  
  
        for (int m=0;m<=CurrServerInfoNumber;m++)  
        {  
          //过滤空元素;  
          //cout<<point_all<<"=="<<*(*(pserver_info+j)+3)<<endl;  
          substrServer=*(*(pserver_info+m)+3);  
          if (idctype=="idc")  
            substrServer=substrServer.substr(0,8);  
          else  
            substrServer=substrServer.substr(0,10);  
          if (point_all==substrServer)  
          {  
            DIVstr+="IP:"+*(*(pserver_info+m)+0)+"<br/>";  
            DIVstr+="操作系统:"+*(*(pserver_info+m)+2)+"<br/>";  
            DIVstr+="位置:"+*(*(pserver_info+m)+3)+"<br/>";  
            DIVstr+="机型:"+*(*(pserver_info+m)+4)+"<br/>";  
            if (*(*(pserver_info+m)+4)=="1U")  
              HTMLstr+="<img src='/images/serverico/"+GetServerCondition(*(*(pserver_info+m)+0),"1U")+"' width='127' height='12' style=\"vertical-align:bottom;\" onmouseover=\"displayDIV('operate"+int2str(allservercount)+"'); return false\" onmouseout=\"hiddenDIV('operate"+int2str(allservercount)+"'); return false\">";  
            else if (*(*(pserver_info+m)+4)=="2U")  
              HTMLstr+="<img src='/images/serverico/"+GetServerCondition(*(*(pserver_info+m)+0),"2U")+"' width='127' height='24' style=\"vertical-align:bottom;\" onmouseover=\"displayDIV('operate"+int2str(allservercount)+"'); return false\" onmouseout=\"hiddenDIV('operate"+int2str(allservercount)+"'); return false\">";  
            else  HTMLstr+="<img src='/images/serverico/"+GetServerCondition(*(*(pserver_info+m)+0),"6U")+"'  height='76' style=\"vertical-align:bottom;\" onmouseover=\"displayDIV('operate"+int2str(allservercount)+"'); return false\" onmouseout=\"hiddenDIV('operate"+int2str(allservercount)+"'); return false\">";  
  
            HTMLstr+="<div id=\"operate"+int2str(allservercount)+"\" style=\"filter:Alpha(opacity=90);display:none;position:absolute; width:200px;BORDER-RIGHT: 2px outset; BORDER-TOP: 1px outset; BACKGROUND: #ffffff; BORDER-LEFT: 1px outset; BORDER-BOTTOM: 2px outset; text-align:left;\"><table cellpadding=\"3\" cellspacing=\"1\"><tr><td>"+DIVstr+"</td></tr></table></div>\n";  
            allservercount+=1;  
            DIVstr="";  
            break;  
          }  
              
        }  
        HTMLstr+=" </td>\n";  
        HTMLstr+="  </tr>\n";  
      }  
      HTMLstr+=" </table>\n";  
      HTMLstr+="</td>\n";  
  
    }  
    HTMLstr+="</tr>\n";  
      HTMLstr+="</table>\n";  
        HTMLstr+="<p> </p>\n";  
  }  
  HTMLstr+="<script src='/js/server_down.js' language='javascript'></script>\n";  
}  
  
//类入 口main(),接受用户参数;  
int main()  
{  
  string * row;  
  string idctype="";  
  
  //定义机柜排号;  
  string IDCA[10]={"01","02","03","04","05","06"};  
  string IDCC[10]={"18","19","20"};  
  
    
  //IDC A  
  idctype="idc";  
  row=IDCA;  
  servermap appa(row,idctype);  
  appa.ProduRow();  
  appa.writefile("idca.html");  
  //IDC C  
  idctype="idc";  
  row=IDCC;  
  servermap appc(row,idctype);  
  appc.ProduRow();  
  appc.writefile("idcc.html");  
  
  //free(p);  
  return 0;  
}

XML数据格式

view plainprint?
<?xml version="1.0" ?><wml>  
<serverinfo>  
  <ip>192.168.0.1</ip>  
  <classid>18</classid>  
  <os>windows-server</os>  
  <locate>CC06-05-08</locate>  
  <body         type>6U</bodytype>  
</serverinfo>  
<serverinfo>  
  <ip>192.168.0.2</ip>  
  <classid>19</classid>  
  <os>linux-server</os>  
  <locate>CC06-05-07-R</locate>  
  <body         type>6U</bodytype>  
</serverinfo>  
<serverinfo>  
  <ip>192.168.0.3</ip>  
  <classid>20</classid>  
  <os>windows-server</os>  
  <locate>CC06-04-07</locate>  
  <body         type>6U</bodytype>  
</serverinfo>  
</wml>

如大家有什么疑问或感兴趣的话题可以通过weibo与我交流http://t.qq.com/yorkoliu

转自:http://blog.liuts.com/post/206/#entrymore

原创文章,作者:s19930811,如若转载,请注明出处:http://www.178linux.com/1755