Commit 7dc2b97a authored by Michael Ott's avatar Michael Ott
Browse files

Initial commit: Config file parsing and IPMI raw query working

parents
/*
* IPMIConnection.cpp
*
* Created on: 18 Jan 2017
* Author: ottmi
*/
#include "IPMIHost.h"
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <freeipmi/freeipmi.h>
#include <freeipmi/api/ipmi-api.h>
namespace DCDB {
IPMIHost::IPMIHost(const std::string hostName) {
_ipmiCtx = NULL;
_hostName = hostName;
_userName = std::string("admin");
_password = std::string("admin");
_auth = IPMI_AUTHENTICATION_TYPE_MD5;
_priv = IPMI_PRIVILEGE_LEVEL_ADMIN;
}
IPMIHost::~IPMIHost() {
}
int IPMIHost::connect() {
if (!(_ipmiCtx = ipmi_ctx_create())) {
printf("ipmi_ctx_create: %s\n", strerror(errno));
return 1;
}
int workaround_flags = 0;
int flags = 0;
/* if (ipmi_ctx_open_outofband(_ipmiCtx, _hostName.c_str(), _userName.c_str(), _password.c_str(), _auth, _priv, 0, 0, workaround_flags, flags) < 0) {*/
if (ipmi_ctx_open_outofband_2_0(_ipmiCtx, _hostName.c_str(), _userName.c_str(), _password.c_str(), NULL, 0, _priv, 3, 0, 0, workaround_flags, flags) < 0) {
printf("ipmi_ctx_open_outofband: %s\n", ipmi_ctx_errormsg(_ipmiCtx));
ipmi_ctx_close(_ipmiCtx);
ipmi_ctx_destroy(_ipmiCtx);
return 2;
}
return 0;
}
uint64_t IPMIHost::sendRawCmd(const std::vector<uint8_t>& rawCmd, uint16_t start, uint16_t stop) {
uint8_t buf[256];
int len;
int i;
if (!IPMI_NET_FN_RQ_VALID(rawCmd[1])) {
std::cout << "Invalid netfn value" << std::endl;
return -1;
}
if (_ipmiCtx == NULL) {
connect();
}
if ((len = ipmi_cmd_raw(_ipmiCtx, rawCmd[0], rawCmd[1], &rawCmd[2], rawCmd.size() - 2, buf, sizeof(buf))) < 0) {
std::cout << "ipmi_cmd_raw: " << ipmi_ctx_errormsg(_ipmiCtx) << std::endl;
return -1;
}
disconnect();
#ifdef DEBUG
std::cout << "IPMIHost::sendRawCmd() received " << len << " bytes: " << std::setw(2) << std::setfill('0') << std::hex;
for (i = 0; i < len; i++) {
std::cout << (unsigned) buf[i] << " ";
}
std::cout << std::dec << std::endl;
#endif
if (stop == 0 || stop >= len) {
stop = len - 1;
}
if ((stop - start) >= 8) {
stop = start + 7;
}
uint64_t val = 0;
for (i = start; i <= stop; i++) {
val |= ((uint64_t) buf[i]) << (stop - i) * 8;
}
return val;
}
int IPMIHost::disconnect() {
if (_ipmiCtx) {
ipmi_ctx_close(_ipmiCtx);
ipmi_ctx_destroy(_ipmiCtx);
_ipmiCtx = NULL;
return 0;
}
return 1;
}
void IPMIHost::addSensor(DCDB::IPMISensor sensor) {
sensor.setHost(this);
_sensors.push_back(sensor);
std::cerr << "IPMIHost::addSensor host=" << this << " sensor=" << &_sensors.back() << std::endl;
}
} /* namespace DCDB */
/*
* IPMIConnection.h
*
* Created on: 18 Jan 2017
* Author: ottmi
*/
#ifndef IPMIHOST_H_
#define IPMIHOST_H_
#include <string>
#include <list>
#include <freeipmi/freeipmi.h>
#include "IPMISensor.h"
namespace DCDB {
class IPMIHost {
public:
IPMIHost(const std::string hostName);
virtual ~IPMIHost();
int connect();
uint64_t sendRawCmd(const std::vector<uint8_t>& rawCmd, uint16_t start, uint16_t stop);
int disconnect();
uint8_t getAuth() const {
return _auth;
}
void setAuth(uint8_t auth) {
_auth = auth;
}
const std::string& getHostName() const {
return _hostName;
}
void setHostName(const std::string& hostName) {
_hostName = hostName;
}
const std::string& getPassword() const {
return _password;
}
void setPassword(const std::string& password) {
_password = password;
}
uint8_t getPriv() const {
return _priv;
}
void setPriv(uint8_t priv) {
_priv = priv;
}
const std::string& getUserName() const {
return _userName;
}
void setUserName(const std::string& userName) {
_userName = userName;
}
void addSensor(DCDB::IPMISensor sensor);
std::list<DCDB::IPMISensor>& getSensors() {
return _sensors;
}
const std::string& getMqttPrefix() const {
return _mqttPrefix;
}
void setMqttPrefix(const std::string& mqttPrefix) {
_mqttPrefix = mqttPrefix;
if (_mqttPrefix.front() != '/') {
_mqttPrefix.insert(0, "/");
}
if (_mqttPrefix.back() == '/') {
_mqttPrefix.erase(_mqttPrefix.size()-1);
}
}
private:
ipmi_ctx_t _ipmiCtx;
std::string _hostName;
std::string _userName;
std::string _password;
uint8_t _auth;
uint8_t _priv;
std::string _mqttPrefix;
std::list<DCDB::IPMISensor> _sensors;
};
} /* namespace DCDB */
#endif /* IPMIHOST_H_ */
/*
* IPMISensor.cpp
*
* Created on: 18 Jan 2017
* Author: ottmi
*/
#include "IPMISensor.h"
#include "IPMIHost.h"
#include <boost/tokenizer.hpp>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <boost/bind.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"
#include <iostream>
namespace DCDB {
IPMISensor::IPMISensor(const std::string& name) {
_name = name;
_freq = 1000;
_start = 0;
_stop = 0;
_host = NULL;
_timer = NULL;
_latestReading = 0;
}
IPMISensor::~IPMISensor() {
// TODO Auto-generated destructor stub
}
uint64_t IPMISensor::query() {
if (_host != NULL) {
boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
_latestReading = _host->sendRawCmd(_rawCmd, _start, _stop);
std::cout << now << " " << _host->getHostName() << "::" << _name << " " << _host->getMqttPrefix() << _mqttSuffix << " => " << _latestReading << std::endl;
return _latestReading;
}
return 0;
}
void IPMISensor::queryAsync() {
query();
if (_timer != NULL) {
_timer->expires_from_now(boost::posix_time::milliseconds(_freq));
_timer->async_wait(boost::bind(&IPMISensor::queryAsync, this));
}
}
void IPMISensor::startPolling(boost::asio::io_service& io) {
_timer = new boost::asio::deadline_timer(io, boost::posix_time::milliseconds(_freq));
std::cout << "Scheduled timer for " << _timer->expires_from_now().seconds() << "(" << _freq << ")" << std::endl;
_timer->async_wait(boost::bind(&IPMISensor::queryAsync, this));
}
void IPMISensor::setRawCmd(std::string& rawCmd) {
boost::regex expr("(?:0x)?([0-9a-fA-F]+)");
boost::regex_token_iterator<std::string::iterator> it{rawCmd.begin(), rawCmd.end(), expr, 1};
boost::regex_token_iterator<std::string::iterator> end;
while (it != end) {
_rawCmd.push_back(stoi(*it++, NULL, 16));
}
}
void IPMISensor::setMqttSuffix(const std::string& mqttSuffix) {
_mqttSuffix = mqttSuffix;
if (_mqttSuffix.front() != '/') {
_mqttSuffix.insert(0, "/");
}
if (_mqttSuffix.back() == '/') {
_mqttSuffix.erase(_mqttSuffix.size()-1);
}
}
} /* namespace DCDB */
/*
* IPMISensor.h
*
* Created on: 18 Jan 2017
* Author: ottmi
*/
#ifndef IPMISENSOR_H_
#define IPMISENSOR_H_
#include <string>
#include <vector>
#include <boost/asio.hpp>
namespace DCDB {
class IPMIHost;
class IPMISensor {
public:
IPMISensor(const std::string& name);
virtual ~IPMISensor();
uint64_t query();
void queryAsync();
void startPolling(boost::asio::io_service& io);
const std::string& getName() const {
return _name;
}
void setName(const std::string& name) {
_name = name;
}
void setRawCmd(std::string& rawCmd);
uint8_t getStart() const {
return _start;
}
void setStart(uint8_t start) {
_start = start;
}
uint8_t getStop() const {
return _stop;
}
void setStop(uint8_t stop) {
_stop = stop;
}
const std::vector<uint8_t>& getRawCmd() const {
return _rawCmd;
}
const DCDB::IPMIHost* getHost() const {
return _host;
}
void setHost(DCDB::IPMIHost* host) {
_host = host;
}
const std::string& getMqttSuffix() const {
return _mqttSuffix;
}
void setMqttSuffix(const std::string& mqttSuffix);
uint64_t getFreq() const {
return _freq;
}
void setFreq(uint64_t freq) {
_freq = freq;
}
private:
std::string _name;
uint64_t _freq;
std::vector<uint8_t> _rawCmd;
uint8_t _start;
uint8_t _stop;
std::string _mqttSuffix;
DCDB::IPMIHost* _host;
boost::asio::deadline_timer* _timer;
uint64_t _latestReading;
};
} /* namespace DCDB */
#endif /* IPMISENSOR_H_ */
TARGET = ipmipusher
DCDBBASEPATH ?= $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/..)
DCDBCOREPATH ?= $(DCDBBASEPATH)/dcdb
FREEIPMI_VERSION = 1.5.5
DISTFILES = freeipmi-$(FREEIPMI_VERSION).tar.gz;http://ftp.gnu.org/gnu/freeipmi/freeipmi-1.5.5.tar.gz
DISTFILES_HASHES = freeipmi-1.5.5.tar.gz|b8abfefee0b757f351d8fab777e3c1bb
include $(DCDBCOREPATH)/common.mk
CXXFLAGS = -O2 -g -Wall $(CXX11FLAGS) -I$(DCDBDEPLOYPATH)/include/ -I$(DCDBBASEPATH)/include -I../deps/freeipmi-$(FREEIPMI_VERSION)/libfreeipmi/include -I../deps/freeipmi-$(FREEIPMI_VERSION)/libfreeipmi/api
OBJS = ipmipusher.o IPMISensor.o IPMIHost.o
LIBS = -L$(DCDBDEPLOYPATH)/lib/ -lpthread -lfreeipmi -lboost_regex -lboost_system -lboost_date_time
TARGET = ipmipusher
$(DCDBDEPSPATH)/freeipmi-$(FREEIPMI_VERSION)/.installed: $(DCDBDEPSPATH)/freeipmi-$(FREEIPMI_VERSION)/.patched
echo ""
echo "Building FreeIPMI library..."
cd $(@D) && ./configure --prefix=$(DCDBDEPLOYPATH)
cd $(@D) && make -j $(MAKETHREADS) libfreeipmi && touch $(@)
$(TARGET): $(foreach f,$(DISTFILESPATHS),$(DCDBDEPSPATH)/$(f)/.installed) $(OBJS)
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(TARGET)
install: $(TARGET)
install $(TARGET) $(DCDBDEPLOYPATH)/bin/
sensors
{
sensor energy {
type raw
freq 1000
cmd "0x00 0x2e 0x81 0x4d 0x4f 0x00 0x00 0x01 0x82 0x00 0x08"
start 5
stop 12
mqttsuffix 99887766
}
}
hosts {
host localhost {
username "USERID"
password "PASSW0RD"
mqttprefix "/00/11/2233445566/778899AA"
sensors {
sensor energy {
MQTTsuffix 11223344
}
}
}
; host test {
; username "USERID"
; password "PASSWORD"
; }
}
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <string>
#include <map>
#include <list>
#include <exception>
#include <iostream>
#include <unistd.h>
#include "IPMIHost.h"
#include "IPMISensor.h"
std::list<DCDB::IPMIHost> hosts;
typedef std::map<std::string, DCDB::IPMISensor> sensorMap_t;
sensorMap_t sensors;
boost::asio::io_service io;
int parseConfig(std::string cfgFile) {
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgFile, cfg);
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("sensors")) {
std::cout << sensor.first << std::endl;
if (boost::iequals(sensor.first, "sensor")) {
std::cout << "Sensor " << sensor.second.data() << std::endl;
if (!sensor.second.empty()) {
DCDB::IPMISensor ipmiSensor(sensor.second.data());
if (boost::iequals(sensor.second.get<std::string>("type"), "raw")) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &s, sensor.second) {
std::cout << " " << s.first << " " << s.second.data() << std::endl;
if (boost::iequals(s.first, ("cmd"))) {
ipmiSensor.setRawCmd(s.second.data());
} else if (boost::iequals(s.first, "freq")) {
ipmiSensor.setFreq(stoi(s.second.data()));
} else if (boost::iequals(s.first, "start")) {
ipmiSensor.setStart(stoi(s.second.data()));
} else if (boost::iequals(s.first, "stop")) {
ipmiSensor.setStop(stoi(s.second.data()));
} else if (boost::iequals(s.first, "mqttsuffix")) {
ipmiSensor.setMqttSuffix(s.second.data());
}
}
}
sensors.insert(sensorMap_t::value_type(ipmiSensor.getName(), ipmiSensor));
}
}
}
BOOST_FOREACH(boost::property_tree::iptree::value_type &host, cfg.get_child("hosts")) {
if (boost::iequals(host.first, ("host"))) {
std::cout << "Host " << host.second.data() << std::endl;
hosts.push_back(DCDB::IPMIHost(host.second.data()));
DCDB::IPMIHost &ipmiHost = hosts.back();
if (!host.second.empty()) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &h, host.second) {
std::cout << " " << h.first << " " << h.second.data() << std::endl;
if (boost::iequals(h.first, "username")) {
ipmiHost.setUserName(h.second.data());
} else if (boost::iequals(h.first, "password")) {
ipmiHost.setPassword(h.second.data());
} else if (boost::iequals(h.first, "sensors")) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &s, h.second) {
std::cout << " " << s.first << " " << s.second.data() << std::endl;
sensorMap_t::iterator it = sensors.find(s.second.data());
if (it != sensors.end()) {
DCDB::IPMISensor sensor = it->second;
boost::optional< boost::property_tree::iptree& > mqtt = s.second.get_child_optional("mqttsuffix");
if (mqtt) {
sensor.setMqttSuffix(mqtt.get().data());
}
ipmiHost.addSensor(sensor);
}
}
} else if (boost::iequals(h.first, "mqttprefix")) {
ipmiHost.setMqttPrefix(h.second.data());
}
}
}
}
}
return 0;
}
void runTask(const boost::system::error_code& e, boost::asio::deadline_timer* t, DCDB::IPMISensor* sensor) {
t->expires_from_now(boost::posix_time::seconds(5));
std::cout << sensor->getHost()->getHostName() << "::" << sensor->getName() << " (" << sensor->getHost()->getMqttPrefix() << sensor->getMqttSuffix() << ") : " << sensor->query() << std::endl;
t->async_wait(boost::bind(runTask, boost::asio::placeholders::error, t, sensor));
}
int main (int argc, char **argv) {
parseConfig("ipmipusher.conf");
BOOST_FOREACH(DCDB::IPMIHost &host, hosts) {
std::cout << "Host " << host.getHostName() << std::endl;
BOOST_FOREACH(DCDB::IPMISensor& sensor, host.getSensors()) {
sensor.startPolling(io);
//t.async_wait(boost::bind(runTask, boost::asio::placeholders::error, &t, &sensor));
}
}
io.run();
/*
BOOST_FOREACH(DCDB::IPMIHost &host, hosts) {
host.disconnect();
}
*/
return 0;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment