实现真实的机柜模拟图[原创]
本帖最后由 phpcool 于 2010-07-09 23:40 编辑
一般能反映机房设备位置、结构我们都喜欢通过网络拓扑图来展现,但个人感觉还不够直观、明了的表现出自己想要的结果(自己太挑剔了,呵呵)。因此写一个生成真实机柜模拟图平台,实现与真实服务器外观、服务状态、空闲位置等信息。
系统截图
1、平台显示某一排截图
2、平台显示某台服务器详细信息截图
3、状态说明
2U服务器正常状态
2U服务器当机状态
系统原理
通过获取运维平台的服务器信息(包括位置、操作系统、机型等),格式为XML,通过c++的tinyxml来解析并渲染成比较美观的HTML格式。当机的信息通过Nagios来获取。这样就可以生成非常人性化的展现平台了:)
系统代码Servermap.cpp
- /***************************************************************************
- * 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数据格式
- <?xml version="1.0" ?><wml>
- <serverinfo>
- <ip>192.168.0.1</ip>
- <classid>18</classid>
- <os>windows-server</os>
- <locate>CC06-05-08</locate>
- <bodytype>6U</bodytype>
- </serverinfo>
- <serverinfo>
- <ip>192.168.0.2</ip>
- <classid>19</classid>
- <os>linux-server</os>
- <locate>CC06-05-07-R</locate>
- <bodytype>6U</bodytype>
- </serverinfo>
- <serverinfo>
- <ip>192.168.0.3</ip>
- <classid>20</classid>
- <os>windows-server</os>
- <locate>CC06-04-07</locate>
- <bodytype>6U</bodytype>
- </serverinfo>
- </wml>
复制代码
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
回复 1# phpcool
很好的想法,支持!
项目已开源,托管地址:
http://code.google.com/p/servermap/
初接触c++,N人勿笑。
学习
明白了,这块可能是个硬伤,我现在在琢磨用图形来实现链路联通的实时报警,有一种方法就是用cacti里的weathermap实现,还没有发现其他更好的方法,而我们机房的报警就直接用nagios的MAP,另外关于机房的位置图有一个国产软件叫visualnet
当机清单存放在ServerDownlist文件中,由于Nagios不提供当机清单接口(如新版有请告知),目前通过一个比较笨的方法来实现,就是分析页面再将IP导入到ServerDownlist文件。
string mainpath="ServerDownlist";
我发现
//返回服务器状态图片;
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";
}
是控制主机显示DOWN或NORMAL,如何和nagios结合起来用呢??
突然发现,很像自己编程的 what's up
本帖最后由 初学vb 于 2010-07-11 00:37 编辑
我做图能力和编程能力是比较差的,但又很想做个测试,所以站短了,谢谢,目前我们自己的监控就是用nagios的页面,我有个想法,如果能测试成功的话,理论上可以把带宽监控加进来,nagios上可以做个PING监控,HTML显示上有问题就红线,没问题就绿线,可以实现实时监控。
不得不说,你这个还挺靠谱,能拿来主义吗?