Implemented logic to avoid too much updates within interval.
("host",po::value<string>(),"The hostname to update.")
("login",po::value<string>(),"Login name.")
("password",po::value<string>(),"Corresponding password.")
+ ("update_interval",po::value<int>()->default_value(-1),"Update interval in minutes.")
+ ("max_updates_within_interval",po::value<int>()->default_value(-1),"How many updates can be made in one interval.")
;
// Available command line only options
BOOST_FOREACH(Service::Ptr &service, OldServices)
{
- if ( ( service->get_lastupdated() + service->get_timeout() ) >= current_time ) // Update Timeout of service isn't expired.
+ if ( ( service->get_last_updates()->front() + (service->get_update_interval()*60) ) >= current_time ) // UpdateInterval timeout of service isn't expired.
service_holder->add_service(service);
}
BOOST_FOREACH(Service::Ptr &old_service, _old_services)
{
OldServices.push_back(old_service);
- Log->print_service_object("Deserialized following Service object:", old_service->get_protocol(), old_service->get_hostname(), old_service->get_login() ,old_service->get_password() ,old_service->get_actual_ip(), old_service->get_lastupdated());
+ Log->print_service_object("Deserialized following Service object:", old_service->get_protocol(), old_service->get_hostname(), old_service->get_login() ,old_service->get_password(), old_service->get_update_interval(), old_service->get_max_updates_within_interval(), old_service->get_actual_ip(), old_service->get_last_updates());
BOOST_FOREACH(Service::Ptr &service, Services)
{
if ( *service == *old_service )
{
- service->set_lastupdated(old_service->get_lastupdated());
+ service->set_last_updates(old_service->get_last_updates());
service->set_actual_ip(old_service->get_actual_ip());
- Log->print_service_object("New Service object with adopted values:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password() ,service->get_actual_ip(), service->get_lastupdated());
+ Log->print_service_object("New Service object with adopted values:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_actual_ip(), service->get_last_updates());
// We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized.
- old_service->set_lastupdated(0);
- old_service->set_timeout(0);
+ old_service->set_update_interval(0);
}
}
}
protocol = ba::to_lower_copy(protocol);
- Service::Ptr service = create_service(protocol,host,login,password);
+ int update_interval = 0;
+ if ( VariablesMap.count("update_interval") )
+ update_interval = VariablesMap["update_interval"].as<int>();
+
+ int max_updates_within_interval = 0;
+ if ( VariablesMap.count("max_updates_within_interval") )
+ max_updates_within_interval = VariablesMap["max_updates_within_interval"].as<int>();
+
+ Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval);
if ( service )
Services.push_back(service);
else
Log->print_usage(OptDescCmd);
return -1;
}
+ catch(po::multiple_occurrences e)
+ {
+ Log->print_multiple_cmd_option(e.what());
+ Log->print_usage(OptDescCmd);
+ return -1;
+ }
return 0;
}
* @param password Password.
* @return A pointer to the created Service object.
*/
-Service::Ptr Config::create_service(const string &protocol,const string &hostname, const string &login, const string &password)
+Service::Ptr Config::create_service(const string &protocol,const string &hostname, const string &login, const string &password, const int update_interval, const int max_updates_within_interval)
{
if(protocol == "dhs")
{
- Service::Ptr service_dhs(new DHS(protocol,hostname,login,password,Log,0,60,1));
+ Service::Ptr service_dhs(new DHS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval));
return service_dhs;
}
else if(protocol == "ods")
{
- Service::Ptr service_ods(new ODS(protocol,hostname,login,password,Log,0,60,1));
+ Service::Ptr service_ods(new ODS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval));
return service_ods;
}
else
protocol = ba::to_lower_copy(protocol);
- Service::Ptr service = create_service(protocol,host,login,password);
+ int update_interval = 0;
+ if ( VariablesMap.count("update_interval") )
+ update_interval = VariablesMap["update_interval"].as<int>();
+
+ int max_updates_within_interval = 0;
+ if ( VariablesMap.count("max_updates_within_interval") )
+ max_updates_within_interval = VariablesMap["max_updates_within_interval"].as<int>();
+
+ Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval);
if ( service )
{
Services.push_back(service);
- Log->print_service_object("New Service object from config:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password() ,service->get_actual_ip(), service->get_lastupdated());
+ Log->print_service_object("New Service object from config:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_actual_ip(), service->get_last_updates());
}
}
}
std::string WebcheckIpUrl;
std::string WebcheckIpUrlAlt;
- Service::Ptr create_service(const std::string&,const std::string&,const std::string&,const std::string&);
+ Service::Ptr create_service(const std::string&,const std::string&,const std::string&,const std::string&, const int, const int);
int load_main_config_file(const std::string&);
int load_service_config_file(const std::string&);
std::string to_lower(std::string) const;
* Default Constructor, needed for object serialization.
*/
DHS::DHS()
- : Timeout(0)
- , MaxUpdatesWithinTimeout(0)
- , ActualUpdatesWithinTimeout(0)
{
}
* @param _login The login name.
* @param _password The corresponding password.
*/
-DHS::DHS(const string& _protocol, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _lastupdated, const int _timeout, const int _max_updates_per_timeout)
- : Timeout(_timeout)
- , MaxUpdatesWithinTimeout(_max_updates_per_timeout)
- , ActualUpdatesWithinTimeout(0)
+DHS::DHS(const string& _protocol, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval)
{
+ if ( _update_interval == -1 ) // If _update_interval is default po::option_desc (not specified via config)
+ set_update_interval(0); // use default protocol value
+ else
+ set_update_interval(_update_interval);
+
+ if ( _max_updates_within_interval == -1 )
+ set_max_updates_within_interval(0);
+ else
+ set_max_updates_within_interval(_max_updates_within_interval);
+
set_protocol(_protocol);
set_hostname(_hostname);
set_login(_login);
set_password(_password);
set_logger(_logger);
- set_lastupdated(_lastupdated);
}
*/
void DHS::update(const string& ip)
{
- if ( this->get_actual_ip() != ip )
+ // If actual service ip (ip set in last update) differs present host ip, then update
+ if ( get_actual_ip() != ip )
{
- this->get_logger()->print_update_service("DHS");
+ get_logger()->print_update_service("DHS");
if ( perform_update(ip) == 0 )
{
// if update was successful, we need to set the Lastupdated and ActualIP base member.
- this->set_lastupdated(time(NULL));
- this->set_actual_ip(ip);
- this->get_logger()->print_update_service_successful("DHS");
+ get_last_updates()->push_front(time(NULL));
+ set_actual_ip(ip);
+ get_logger()->print_update_service_successful("DHS");
+ }
+ else
+ {
+ // problem while trying to update service
+ // TODO: error logging
}
}
}
void DHS::serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<Service>(*this);
- ar & Timeout;
- ar & MaxUpdatesWithinTimeout;
- ar & ActualUpdatesWithinTimeout;
-}
-
-
-/**
- * Setter for member Timeout.
- * @param _timeout Value to set Timeout to.
- */
-void DHS::set_timeout(const int _timeout)
-{
- Timeout = _timeout;
-}
-
-
-/**
- * Getter for member Timeout.
- * @return Value of Timeout.
- */
-int DHS::get_timeout() const
-{
- return Timeout;
-}
-
-
-/**
- * Setter for member MaxUpdatesWithinTimeout.
- * @param _max_updates_per_timeout Value to set MaxUpdatesWithinTimeout to.
- */
-void DHS::set_max_updates_within_timeout(const int _max_updates_per_timeout)
-{
- MaxUpdatesWithinTimeout = _max_updates_per_timeout;
-}
-
-
-/**
- * Getter for member MaxUpdatesWithinTimeout.
- * @return Value of MaxUpdatesWithinTimeout.
- */
-int DHS::get_max_updates_within_timeout() const
-{
- return MaxUpdatesWithinTimeout;
}
private:
- int Timeout;
- int MaxUpdatesWithinTimeout;
- int ActualUpdatesWithinTimeout;
-
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &, const unsigned int);
DHS();
- DHS(const std::string&, const std::string&, const std::string&, const std::string&, const Logger::Ptr&, const int, const int, const int);
+ DHS(const std::string&, const std::string&, const std::string&, const std::string&, const Logger::Ptr&, const int, const int);
~DHS();
- void set_timeout(const int);
- int get_timeout() const;
-
- void set_max_updates_within_timeout(const int);
- int get_max_updates_within_timeout() const;
-
void update(const std::string&);
int perform_update(const std::string&);
*/
string IPHelper::get_actual_ip() const
{
+ string ip;
if ( WebcheckIpUrl.empty() )
{
- return dns_query();
+ ip = dns_query();
}
else
{
- return webcheck_ip();
+ ip = webcheck_ip();
}
- return "";
+
+ // TODO IF IP is local, then return ""
+
+ return ip;
}
#include <syslog.h>
#include <sstream>
+#include <boost/foreach.hpp>
+
namespace po = boost::program_options;
using namespace std;
* @param actual_ip Service's actual_ip.
* @param lastupdated Service's lastupdated.
*/
-void Logger::print_service_object(const string& message, const string& protocol, const string& hostname, const string& login, const string& password, const string& actual_ip, const int lastupdated) const
+void Logger::print_service_object(const string& message, const string& protocol, const string& hostname, const string& login, const string& password, const int update_interval, const int max_updates_within_interval, const string& actual_ip, list<int>* lastupdated) const
{
if ( 1 <= Loglevel )
{
ostringstream msg;
msg << message << endl;
- msg << "\t" << "Protocol: " << protocol << endl;
- msg << "\t" << "Hostname: " << hostname << endl;
- msg << "\t" << "Login: " <<login << endl;
- msg << "\t" << "Password: " <<password << endl;
- msg << "\t" << "Actual_IP: " <<actual_ip << endl;
- msg << "\t" << "Lastupdated: " <<lastupdated << endl;
+ msg << "\t" << "Protocol: " << protocol << endl;
+ msg << "\t" << "Hostname: " << hostname << endl;
+ msg << "\t" << "Login: " << login << endl;
+ msg << "\t" << "Password: " << password << endl;
+ msg << "\t" << "Update Interval: " << update_interval << endl;
+ msg << "\t" << "Max Updates: " << max_updates_within_interval << endl;
+ msg << "\t" << "Actual_IP: " << actual_ip << endl;
+ BOOST_FOREACH( int update_time, *lastupdated)
+ {
+ msg << "\t" << "Lastupdated: " << update_time << endl;
+ }
log_notice(msg.str());
}
}
log_warning(msg.str());
}
}
+
+
+/**
+ * Detected multiple occurrences of the same option.
+ * @param message Error message.
+ */
+void Logger::print_multiple_cmd_option(const string& message) const
+{
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "The same option is only allowed once: " << message << endl;
+ log_error(msg.str());
+ }
+}
+
+
+/**
+ * An update would exceed the update interval. Prints out a warning message.
+ * @param current_time Current time.
+ * @param old_time Time of update #MaxUpdatesWithinInterval ago.
+ * @param MaxUpdatesWithinInterval Number of allowed updates in one update interval.
+ * @param service The service which exceeds update interval.
+ */
+void Logger::print_update_not_allowed(const int current_time, const int old_time, const int MaxUpdatesWithinInterval, const string& service) const
+{
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Update not allowed for service: " << service << ". Too many updates within max update interval. Current time: " << current_time << ". Update time before " << MaxUpdatesWithinInterval << " updates: " << old_time << endl;
+ log_warning(msg.str());
+ }
+}
+
+
+/**
+ * Failure while running update for service.
+ * @param service Services' name.
+ */
+void Logger::print_update_service_failure(const std::string& service) const
+{
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Could not update service: " << service << endl;
+ log_warning(msg.str());
+ }
+}
void print_deserialized_objects_success() const;
- void print_service_object(const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const int) const;
+ void print_service_object(const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const int, const int, const std::string&, std::list<int>*) const;
void print_exception_serialize(const std::string&) const;
void print_regex_found_ip(const std::string&) const;
void print_regex_ip_not_found(const std::string&) const;
+
+ void print_multiple_cmd_option(const std::string&) const;
+
+ void print_update_not_allowed(const int current_time, const int old_time, const int MaxUpdatesWithinInterval, const std::string& service) const;
+
+ void print_update_service_failure(const std::string& service) const;
};
#endif
{
if ( is_online == true )
{
- // TODO: Get the actual IP of this host (through DNS or WEBCHECK_IP). Perhaps new Class which can handle both.
-
// update all configured services
updater->update_services();
}
* Default Constructor, needed for object serialization.
*/
ODS::ODS()
- : Timeout(0)
- , MaxUpdatesWithinTimeout(0)
- , ActualUpdatesWithinTimeout(0)
{
}
* @param _login The login name.
* @param _password The corresponding password.
*/
-ODS::ODS(const string& _protocol, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _lastupdated, const int _timeout, const int _max_updates_per_timeout)
- : Timeout(_timeout)
- , MaxUpdatesWithinTimeout(_max_updates_per_timeout)
- , ActualUpdatesWithinTimeout(0)
+ODS::ODS(const string& _protocol, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval)
{
+ if ( _update_interval == -1 ) // If _update_interval is default po::option_desc (not specified via config)
+ set_update_interval(15); // use default protocol value
+ else
+ set_update_interval(_update_interval);
+
+ if ( _max_updates_within_interval == -1 )
+ set_max_updates_within_interval(3);
+ else
+ set_max_updates_within_interval(_max_updates_within_interval);
+
set_protocol(_protocol);
set_hostname(_hostname);
set_login(_login);
set_password(_password);
set_logger(_logger);
- set_lastupdated(_lastupdated);
}
*/
void ODS::update(const string& ip)
{
- if ( this->get_actual_ip() != ip )
+ if ( get_actual_ip() != ip )
{
- this->get_logger()->print_update_service("DHS");
+ int current_time = time(NULL);
+ get_logger()->print_update_service("ODS");
- if ( perform_update(ip) == 0 )
+ // test if update is permitted by UpdateInterval Status
+ if ( update_allowed(current_time) )
{
- // if update was successful, we need to set the Lastupdated and ActualIP base member.
- this->set_lastupdated(time(NULL));
- this->set_actual_ip(ip);
- this->get_logger()->print_update_service_successful("DHS");
+
+ if ( perform_update(ip) == 0 )
+ {
+ // if update was successful, we need to set the Lastupdated and ActualIP base member.
+ get_last_updates()->push_front(time(NULL));
+ set_actual_ip(ip);
+ get_logger()->print_update_service_successful("ODS");
+ }
+ else
+ {
+ // problem while trying to update service
+ get_logger()->print_update_service_failure("ODS");
+ }
+
}
}
}
void ODS::serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<Service>(*this);
- ar & Timeout;
- ar & MaxUpdatesWithinTimeout;
- ar & ActualUpdatesWithinTimeout;
-}
-
-
-/**
- * Setter for member Timeout.
- * @param _timeout Value to set Timeout to.
- */
-void ODS::set_timeout(const int _timeout)
-{
- Timeout = _timeout;
-}
-
-
-/**
- * Getter for member Timeout.
- * @return Value of Timeout.
- */
-int ODS::get_timeout() const
-{
- return Timeout;
-}
-
-
-/**
- * Setter for member Max_updates_per_timeout.
- * @param _max_updates_per_timeout Value to set Max_updates_per_timeout to.
- */
-void ODS::set_max_updates_within_timeout(const int _max_updates_per_timeout)
-{
- MaxUpdatesWithinTimeout = _max_updates_per_timeout;
-}
-
-
-/**
- * Getter for member Max_updates_per_timeout.
- * @return Value of Max_updates_per_timeout.
- */
-int ODS::get_max_updates_within_timeout() const
-{
- return MaxUpdatesWithinTimeout;
}
private:
- int Timeout;
- int MaxUpdatesWithinTimeout;
- int ActualUpdatesWithinTimeout;
-
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &, const unsigned int);
ODS();
- ODS(const std::string&, const std::string&, const std::string&, const std::string&, const Logger::Ptr&, const int, const int, const int);
+ ODS(const std::string&, const std::string&, const std::string&, const std::string&, const Logger::Ptr&, const int, const int);
~ODS();
- void set_timeout(const int);
- int get_timeout() const;
-
- void set_max_updates_within_timeout(const int);
- int get_max_updates_within_timeout() const;
-
void update(const std::string&);
int perform_update(const std::string&);
*/
#include "service.h"
-
+#include <boost/foreach.hpp>
+#include <boost/serialization/list.hpp>
/**
* Default Constructor
, Login("NOT SERIALIZED")
, Password("NOT SERIALIZED")
, ActualIP("0.0.0.0")
- , Lastupdated(0)
+ , UpdateInterval(0)
+ , MaxUpdatesWithinInterval(0)
, Log(new Logger())
{
}
ar & Protocol;
ar & Hostname;
// lastupdated and actual_ip must also be serialized, cause these are essential infos of each service.
- ar & Lastupdated;
+ ar & LastUpdates;
ar & ActualIP;
+ ar & UpdateInterval;
+ ar & MaxUpdatesWithinInterval;
}
}
-/**
- * Setter for member Lastupdated.
- * @param _lastupdated Value to set Lastupdated to.
- */
-void Service::set_lastupdated(const int _lastupdated)
+void Service::set_last_updates(std::list<int>* _last_updates)
{
- Lastupdated = _lastupdated;
+ LastUpdates.clear();
+ BOOST_FOREACH( int update_time, *_last_updates )
+ {
+ LastUpdates.push_back(update_time);
+ }
}
* Getter for member Lastupdated.
* @return Value of member Lastupdated.
*/
-int Service::get_lastupdated() const
+list<int>* Service::get_last_updates()
{
- return Lastupdated;
+ return &LastUpdates;
}
{
return !(*this == other);
}
+
+
+/**
+ * Checks if update will exceed max update interval.
+ * @param current_time Current time.
+ * @return True if update is allowed, false if update would exceed max update interval.
+ */
+bool Service::update_allowed(const int current_time)
+{
+ list<int>::iterator iter;
+ int i=0;
+
+ for (iter = LastUpdates.begin(); (iter != LastUpdates.end()) && ( i < MaxUpdatesWithinInterval ); iter++)
+ {
+ if ( (i == (MaxUpdatesWithinInterval-1)) && ( (*iter + (UpdateInterval*60)) >= current_time ) )
+ {
+ Log->print_update_not_allowed(current_time,*iter,MaxUpdatesWithinInterval,"ODS");
+ return false;
+ }
+ i++;
+ }
+ return true;
+}
+
+
+/**
+ * Setter for member Timeout.
+ * @param _timeout Value to set Timeout to.
+ */
+void Service::set_update_interval(const int _update_interval)
+{
+ UpdateInterval = _update_interval;
+}
+
+
+/**
+ * Getter for member Timeout.
+ * @return Value of Timeout.
+ */
+int Service::get_update_interval() const
+{
+ return UpdateInterval;
+}
+
+
+/**
+ * Setter for member Max_updates_per_timeout.
+ * @param _max_updates_per_timeout Value to set Max_updates_per_timeout to.
+ */
+void Service::set_max_updates_within_interval(const int _max_updates_within_interval)
+{
+ MaxUpdatesWithinInterval = _max_updates_within_interval;
+}
+
+
+/**
+ * Getter for member Max_updates_per_timeout.
+ * @return Value of Max_updates_per_timeout.
+ */
+int Service::get_max_updates_within_interval() const
+{
+ return MaxUpdatesWithinInterval;
+}
std::string ActualIP;
- int Lastupdated;
+ int UpdateInterval;
+ int MaxUpdatesWithinInterval;
+
+ std::list<int> LastUpdates;
friend class boost::serialization::access;
template<class Archive>
virtual ~Service();
- virtual void update(const std::string&)=0;
+ virtual void update(const std::string&) = 0;
- virtual int get_timeout()const =0 ;
- virtual void set_timeout(const int)=0;
+ int get_update_interval()const;
+ void set_update_interval(const int);
- virtual int get_max_updates_within_timeout() const =0;
- virtual void set_max_updates_within_timeout(const int)=0;
+ int get_max_updates_within_interval() const;
+ void set_max_updates_within_interval(const int);
void set_protocol(const std::string&);
std::string get_protocol() const;
void set_password(const std::string&);
std::string get_password() const;
- void set_lastupdated(const int);
- int get_lastupdated() const;
+ void set_last_updates(std::list<int>*);
+ std::list<int>* get_last_updates();
void set_actual_ip(const std::string&);
std::string get_actual_ip() const;
void set_logger(const Logger::Ptr&);
Logger::Ptr get_logger() const;
+ bool update_allowed(const int current_time);
+
bool operator== (const Service&) const;
bool operator!= (const Service&) const;
};
string ip = IPHelp->get_actual_ip();
- BOOST_FOREACH(Service::Ptr &service, services )
+ if ( !ip.empty() )
{
- // TODO: only update if IP differs and is_valid and is_not_empty.
- service->update(ip);
+ BOOST_FOREACH(Service::Ptr &service, services )
+ {
+ service->update(ip);
+ }
}
}