Qt开发之路——基于RedfishAPI的服务器管理小应用
基于Redfish的服務(wù)器管理小應(yīng)用
- 前言
- 關(guān)于ipmi
- 關(guān)于Redfish
- 關(guān)于RedfishAPI
- 效果
- 開發(fā)環(huán)境
- 功能介紹
- 技術(shù)
- Qt樣式表
- 信號(hào)槽
- treeWidget的使用
- https請求及解析
- QSlite數(shù)據(jù)庫的使用
- 參考
前言
本文介紹了近期完成的一個(gè)小項(xiàng)目——基于Redfish的服務(wù)器管理小應(yīng)用。一方面記錄一下自己的開發(fā)經(jīng)歷;另一方面本項(xiàng)目適用于準(zhǔn)備學(xué)習(xí)樣式表,信號(hào)槽,treeWidget,https請求,SQlite數(shù)據(jù)庫的人。代碼在最下方。
注:公司內(nèi)部網(wǎng)絡(luò)才可以訪問redfish接口,項(xiàng)目的網(wǎng)絡(luò)請求無法發(fā)送成功,所以關(guān)于https請求部分僅供參考,也可以參看Qt開發(fā)之路——Json解析過程中遇到的readAll()清除內(nèi)存緩沖區(qū)問題~
關(guān)于ipmi
IMPI(智能平臺(tái)管理接口)是一種嵌入式功能,同時(shí)也是工業(yè)標(biāo)準(zhǔn),由英特爾與戴爾、惠普和NEC合作開發(fā),可實(shí)現(xiàn)對服務(wù)器的遠(yuǎn)程控制。但是這種規(guī)范也有它的局限性,層出不窮的安全問題使得它自從2015年更新2.0后沒有再翻新,與此同時(shí)Redfish興起。
關(guān)于Redfish
Redfish是由分布式管理任務(wù)組(DMTF)發(fā)布的開放式行業(yè)標(biāo)準(zhǔn)規(guī)范,旨在對平臺(tái)硬件進(jìn)行現(xiàn)代化和安全的管理,是一種管理標(biāo)準(zhǔn),在超媒體RESTful接口中使用數(shù)據(jù)模型表示。它是一個(gè)超媒體API,所以它能夠通過一個(gè)一致的接口來表示各種實(shí)現(xiàn)。它有管理數(shù)據(jù)中心資源、處理事件、長期任務(wù)和發(fā)現(xiàn)的機(jī)制。初識(shí)Redfish
關(guān)于RedfishAPI
RedfishAPI代表了一種新的編程風(fēng)格,它能夠以一致的方式管理從超級(jí)規(guī)模到刀片服務(wù)器再到獨(dú)立服務(wù)器的系統(tǒng)。
對于背景可以移步https://blog.csdn.net/asmartkiller/article/details/106558952作更細(xì)致的了解。
效果
開發(fā)環(huán)境
應(yīng)用:Qt Creator 4.11.1(Community)
開發(fā)環(huán)境:MinGW_32_bit
數(shù)據(jù)庫:SQlite
功能介紹
添加服務(wù)器:
初始化:刪除所有服務(wù)器
幫助:簡單顯示服務(wù)器小助手的功能
右鍵刷新告警及開關(guān)機(jī)狀態(tài)信息(再次請求系統(tǒng)信息和告警信息,即兩個(gè)get請求):
右鍵刪除服務(wù)器
技術(shù)
1、Qt樣式表,信號(hào)槽
2、通過treewidget組件顯示數(shù)據(jù)。
3、通過解析https請求到的JSON數(shù)據(jù)獲取相對應(yīng)的特征信息。
4、將數(shù)據(jù)存儲(chǔ)在Qt自帶的SQlite數(shù)據(jù)庫中,方便讀取和刪除。
Qt樣式表
因?yàn)槌绦虮容^小,且界面不多,所以樣式表直接在設(shè)計(jì)器里實(shí)現(xiàn)的。
比如存儲(chǔ)按鈕的點(diǎn)擊狀態(tài)
信號(hào)槽
為了便于統(tǒng)一管理,將信號(hào)和槽寫在main函數(shù)中。主要用于界面之間的切換和值傳遞。
/* + functionui from widget to addid for adding servers*/QObject::connect(w,SIGNAL(showAddId()),i,SLOT(receive_widget_addid()));/* save functionui from addid to widget for showing servers data*/QObject::connect(i,SIGNAL(showLabel(QString,QString,QString,QString,QString,QString)),w,SLOT(receive_save(QString,QString,QString,QString,QString,QString)));/* cancel functionui from addid to widget for showing widget*/QObject::connect(i,SIGNAL(showWidget()),w,SLOT(receive_addid_cancel()));/* show loading uiui from addid to loading for showing waiting process*/QObject::connect(i,SIGNAL(showLoading()),l,SLOT(receive_addid_loading()));/* close loading uiui from addid to loading for showing widget ui*/QObject::connect(i,SIGNAL(closeLoading()),l,SLOT(receive_addid_closeloading()));/* refresh realdataui from widget to addid for refreshing realdata——powerstate and serveritynum*/QObject::connect(w,SIGNAL(refresh_realtimedata(QString)),i,SLOT(receive_widget_refresh(QString)));/* refresh realdataui from addid to widget for sending realdata——powerstate and serveritynum*/QObject::connect(i,SIGNAL(send_realTimeData(QString,QString)),w,SLOT(receive_realTimeData(QString,QString)));treeWidget的使用
添加一行
QStringList strs;strs<<QString("******")<<QString("*********")<<QString(powerstate)<<QString(severity)<<QString("***************");//set the header to appropriate sizeQHeaderView *head=ui->treeWidget->header();head->setSectionResizeMode(QHeaderView::ResizeToContents);//add one line for treewidget,content is strsQTreeWidgetItem *strsroot = new QTreeWidgetItem(ui->treeWidget,strs);//set currentitemui->treeWidget->setCurrentItem(strsroot);刪除一行
QTreeWidgetItem *item = ui->treeWidget->currentItem(); delete(item);刪除treewidget的所有數(shù)據(jù)
//delete the treewidget for uiui->treeWidget->clear();https請求及解析
https請求:QNetworkRequest、QNetworkAccessManager、QNetworkReply、QEventLoop
JSON解析:QJsonDocument、QJsonParseError、QJsonObject、QJsonArray、QJsonValue
主要涉及到對三種形式JSON數(shù)據(jù)的解析。涉及到3條url,這里記為url1,url2,url3。首先獲取token,然后根據(jù)token和url2發(fā)送get請求先后獲取產(chǎn)品名稱,開關(guān)機(jī)狀態(tài),健康狀態(tài)以及uuid。通過url3和token獲取服務(wù)器告警信息。
url1及用戶名密碼發(fā)送post請求獲取token:
得到如下形式的JSON數(shù)據(jù):
{"@odata.context": "/redfish/v1/$metadata#Session.Session","@odata.id": "/redfish/v1/****/*********","@odata.type": "#Session.*****.Session","Id": "********","Name": "User Session","Description": "Manager User Session","UserName": "****","SessionType": "Redfish","Oem": {"BMC": {"LoginTime": "2021-01-04T11:30:51+08:00\n","ClientAddress": "****","ServerAddress": "id","SessionId": "*****","EnabledHttps": true,"Role": "Administrator","Location": "/redfish/v1/*****/*************","X-Auth-Token": "lhe6Gqi4Lz2CA7rx15vc0IRNh22iz4Vb","UserId": 2}} }解析獲取認(rèn)證X-Token
/*analysis SessionsJson for token url1 */ QString AddId::analysisSessionsJson(QNetworkReply *reply){//judge if format of the json is rightif (reply->error() == QNetworkReply::NoError){QByteArray bytes = reply->readAll(); //read all bytesQJsonParseError jsonError_login;//switch to json documentQJsonDocument document = QJsonDocument::fromJson(bytes, &jsonError_login);//analysis Json errorif (document.isObject()){QJsonObject obj = document.object();if (obj.contains("Oem")){QJsonObject object_value = obj.value("Oem").toObject();if (object_value.contains("BMC")){QJsonObject object1_value = object_value.value("BMC").toObject();if(object1_value.contains("X-Auth-Token")){QString token_val = object1_value.value("X-Auth-Token").toString();return token_val;}}}}} }url2及token發(fā)送get請求獲取系統(tǒng)信息:
QStringList AddId::getCriticalMsg(QString url,QString token) {QNetworkRequest request;QSslConfiguration config;QSslConfiguration conf = request.sslConfiguration();conf.setPeerVerifyMode(QSslSocket::VerifyNone);conf.setProtocol(QSsl::TlsV1SslV3);request.setSslConfiguration(conf);request.setUrl(QUrl("https://www.baidu.com"));//set url and xAuthTokenrequest.setUrl(QUrl(url));request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");request.setRawHeader(QByteArray("X-Auth-Token"),QByteArray(token.toUtf8()));QNetworkReply *systeminfo = manager->get(request);//if no below three codes,will first run the latter code after QNetworkReply *systeminfo = manager->get(request);then to run replyQEventLoop eventLoop;connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);eventLoop.exec();QStringList criticalstr = analysisSystemJson(systeminfo);return criticalstr; }得到如下形式的JSON數(shù)據(jù):
{"@odata.context": "/redfish/v1/$metadata#ComputerSystem.ComputerSystem","@odata.id": "/redfish/v1/******","@odata.type": "#ComputerSystem.ComputerSystem","Id": "1","Name": "Computer System","Actions": {"ResetType@Redfish.AllowableValues": ["On","ForceOff","ForceRestart","GracefulShutdown","ForcePowerCycle","Nmi"],"target": "/redfish/v1/*******"},"AssetTag": "******","Manufacturer": "********","Model": "********","SerialNumber": "********","PartNumber": "********","HostingRole": "ApplicationServer","SystemType": "Physical","UUID": "4********","HostName": "********","PowerState": "On","PowerRestorePolicyTypes": "LastState","IndicatorLED": "Off","BIOSVersion": "********","Status": {"State": "Enabled","Health": "OK"} }解析得到Manufacturer,PowerState,UUID,Health
/*analysis processing*url2 for product name,state of on or off,warnings num,GUID*/ QStringList AddId::analysisSystemJson(QNetworkReply *sys){QStringList criticalstr;if (sys->error() == QNetworkReply::NoError){QByteArray bytes = sys->readAll();QJsonParseError jsonError_system;QJsonDocument document = QJsonDocument::fromJson(bytes, &jsonError_system);if (document.isObject()){QJsonObject obj = document.object();if (obj.contains("Manufacturer")) {QString manufacturer = obj.value("Manufacturer").toString();criticalstr.append(manufacturer);qDebug() << manufacturer;}if (obj.contains("PowerState")) {QString powerstate = obj.value("PowerState").toString();criticalstr.append(powerstate);qDebug() << powerstate;}if (obj.contains("UUID")) {QString uuid = obj.value("UUID").toString();criticalstr.append(uuid);qDebug() << uuid;}if (obj.contains("Status")){QJsonObject object_value = obj.value("Status").toObject();if (object_value.contains("Health")){QString health = object_value.value("Health").toString();criticalstr.append(health);qDebug() << health;}}}} }通過url3和token發(fā)送get請求獲取告警率:
QString AddId::getSeverityMsg(QString url,QString token) {QNetworkRequest request;QSslConfiguration config;QSslConfiguration conf = request.sslConfiguration();conf.setPeerVerifyMode(QSslSocket::VerifyNone);conf.setProtocol(QSsl::TlsV1SslV3);request.setSslConfiguration(conf);request.setUrl(QUrl("https://www.baidu.com"));//set url and xAuthTokenrequest.setUrl(QUrl(url));request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");request.setRawHeader(QByteArray("X-Auth-Token"),QByteArray(token.toUtf8()));QNetworkReply *logserverinfo = manager->get(request);//if no below three codes,will first run the latter code after QNetworkReply *systeminfo = manager->get(request);then to run replyQEventLoop eventLoop;connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);eventLoop.exec();QString healthrate = analysisLogServerJson(logserverinfo);return healthrate; }得到如下形式的JSON數(shù)據(jù):
{"@odata.context": "/redfish/v1/******","@odata.id": "redfish/v1/******","@odata.type": "#LogEntryCollection.LogEntryCollection","Description": "Collection of entries for this log service","Name": "Log Service Entries Collection","Members@odata.count": 24,"Members": [{"@odata.id": "/redfish/v1/******/24","Id": "24","Name": "Log Entry 24","EntryType": "******","SensorNumber": 186,"Created": "2021-01-04T07:14:12","EventTimestamp": "2021-01-04T07:14:12","Severity": "Ok","EntryCode": "Assert","SensorType": "******/Interconnect","Message": "******/Interconnect is connected"},{"@odata.id": "/redfish/v1/******","Id": "23","Name": "Log Entry 23","EntryType": "SEL","SensorNumber": 184,"Created": "2021-01-04T07:14:12","EventTimestamp": "2021-01-04T07:14:12","Severity": "Ok","EntryCode": "Assert","SensorType": "******/Interconnect","Message": "******/Interconnect is connected"},...........] }解析獲得Severity = ok的數(shù)量和 不等于ok(嚴(yán)重告警)的數(shù)量。
/*get request*https://id/redfish/v1/Systems for product name,state of on or off,warnings num,GUID*/ QString AddId::analysisLogServerJson(QNetworkReply *logserver){int serveritynum = 0;int healthnum = 0;qint32 logcount = 0;if (logserver->error() == QNetworkReply::NoError){QByteArray bytes = logserver->readAll();QJsonParseError jsonError_logserver;QJsonDocument document = QJsonDocument::fromJson(bytes, &jsonError_logserver);if (document.isObject()){QJsonObject obj = document.object();if (obj.contains("Members@odata.count")){//note that value for "Members@odata.count" is not a stringlogcount = obj.value("Members@odata.count").toInt();}if (obj.contains("Members")){QJsonValue members = obj.value("Members");//the value of members is a arrayif(members.isArray()){for(int i = 0;i< logcount;i++){QJsonObject members_obj = members.toArray().at(i).toObject();if(members_obj.contains("Severity")){QString status_value = members_obj.value("Severity").toString();if(!(status_value == "Ok")){serveritynum +=1;}else{healthnum +=1;}}}}}}}QSlite數(shù)據(jù)庫的使用
QSqlDatabase、QSqlQuery、QSqlError、QSqlTableModel
Qt開發(fā)之路——SQlite的使用(簡單粗暴)
github:https://github.com/hqy7777/SMS-Based-On-Redfish-Qt
參考
Qt開發(fā)之路——Json解析過程中遇到的readAll()清除內(nèi)存緩沖區(qū)問題
Qt開發(fā)之路——SQlite的使用(簡單粗暴)
歡迎討論交流~
總結(jié)
以上是生活随笔為你收集整理的Qt开发之路——基于RedfishAPI的服务器管理小应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言正交表测试用例,测试用例设计之正交
- 下一篇: 使用SubSonic生成数据访问层步骤