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