added option min-time-between-resolves-option and tests for it
[pingcheck] / src / config / configurationoptions.cpp
1 /*
2  The software in this package is distributed under the GNU General
3  Public License version 2 (with a special exception described below).
4
5  A copy of GNU General Public License (GPL) is included in this distribution,
6  in the file COPYING.GPL.
7
8  As a special exception, if other files instantiate templates or use macros
9  or inline functions from this file, or you compile this file and link it
10  with other works to produce a work based on this file, this file
11  does not by itself cause the resulting work to be covered
12  by the GNU General Public License.
13
14  However the source code for this file must still be made available
15  in accordance with section (3) of the GNU General Public License.
16
17  This exception does not invalidate any other reasons why a work based
18  on this file might be covered by the GNU General Public License.
19  */
20
21 #include "config/configurationoptions.h"
22
23 #include <iostream>
24
25 #include <boost/foreach.hpp>
26
27 #include <logfunc.hpp>
28
29 #include "boost_assert_handler.h"
30 #include "config/option/configfileoption.h"
31 #include "config/option/daemonoption.h"
32 #include "config/option/hostsdownlimitoption.h"
33 #include "config/option/hostnameoption.h"
34 #include "config/option/hostportoption.h"
35 #include "config/option/hostpingprotocoloption.h"
36 #include "config/option/hostpingintervaloption.h"
37 #include "config/option/hostsourcenetworkinterfaceoption.h"
38 #include "config/option/linkdownintervaloption.h"
39 #include "config/option/linkupintervaloption.h"
40 #include "config/option/logleveloption.h"
41 #include "config/option/logoutputoption.h"
42 #include "config/option/logfileoption.h"
43 #include "config/option/nameserveroption.h"
44 #include "config/option/pingfaillimitoption.h"
45 #include "config/option/sourcenetworkinterfaceoption.h"
46 #include "config/option/statusnotifiercmdoption.h"
47 #include "config/option/versionoption.h"
48 #include "config/option/ratiorandomhostsoption.h"
49 #include "config/option/pingreplytimeoutoption.h"
50 #include "config/option/maxaddressresolutionattemptsoption.h"
51 #include "config/option/resolvedipttlthresholdoption.h"
52 #include "config/option/mintimebetweenresolvesoption.h"
53 #include "config/option/dnscachefileoption.h"
54
55 using namespace std;
56 using boost::program_options::option_description;
57 using boost::program_options::options_description;
58 using boost::program_options::value;
59 using boost::program_options::variables_map;
60 using boost::shared_ptr;
61 using I2n::Logger::GlobalLogger;
62
63 //-----------------------------------------------------------------------------
64 // ConfigurationOptions
65 //-----------------------------------------------------------------------------
66
67 /**
68  * @brief Default constructor.
69  */
70 ConfigurationOptions::ConfigurationOptions() :
71     GenericOptions(),
72     ConfigOptions(),
73     HostOptions(),
74     HelpCmdStr( "help" ),
75     HelpCmdDesc( "Print this help and exit." )
76 {
77     ConfigurationOptionItem config_file( new ConfigFileOption );
78     GenericOptions.push_back( config_file );
79
80     ConfigurationOptionItem daemon( new DaemonOption );
81     GenericOptions.push_back( daemon );
82
83     ConfigurationOptionItem version( new VersionOption );
84     GenericOptions.push_back( version );
85
86     ConfigurationOptionItem log_level( new LogLevelOption );
87     GenericOptions.push_back( log_level );
88
89     ConfigurationOptionItem log_output( new LogOutputOption );
90     GenericOptions.push_back( log_output );
91
92     ConfigurationOptionItem log_file( new LogFileOption );
93     GenericOptions.push_back( log_file );
94
95     ConfigurationOptionItem hosts_down_limit( new HostsDownLimitOption );
96     ConfigOptions.push_back( hosts_down_limit );
97
98     ConfigurationOptionItem link_down_interval( new LinkDownIntervalOption );
99     ConfigOptions.push_back( link_down_interval );
100
101     ConfigurationOptionItem link_up_interval( new LinkUpIntervalOption );
102     ConfigOptions.push_back( link_up_interval );
103
104     ConfigurationOptionItem nameserver( new NameserverOption );
105     ConfigOptions.push_back( nameserver );
106
107     ConfigurationOptionItem ping_fail_limit( new PingFailLimitOption );
108     ConfigOptions.push_back( ping_fail_limit );
109
110     ConfigurationOptionItem source_network_interface( new SourceNetworkInterfaceOption );
111     ConfigOptions.push_back( source_network_interface );
112
113     ConfigurationOptionItem status_notifier_cmd( new StatusNotifierCmdOption );
114     ConfigOptions.push_back( status_notifier_cmd );
115
116     ConfigurationOptionItem ping_reply_timeout( new PingReplyTimeoutOption );
117     ConfigOptions.push_back( ping_reply_timeout );
118
119     ConfigurationOptionItem max_address_resolution_attempts( new MaxAddressResolutionAttemptsOption );
120     ConfigOptions.push_back( max_address_resolution_attempts );
121
122     ConfigurationOptionItem resolved_ip_ttl_threshold( new ResolvedIpTtlThresholdOption );
123     ConfigOptions.push_back( resolved_ip_ttl_threshold );
124
125     ConfigurationOptionItem min_time_between_resolves( new MinTimeBetweenResolvesOption );
126     ConfigOptions.push_back( min_time_between_resolves );
127
128     ConfigurationOptionItem ratio_random_hosts( new RatioRandomHostsOption );
129     ConfigOptions.push_back( ratio_random_hosts );
130
131     ConfigurationOptionItem dns_cache_file( new DnsCacheFileOption );
132     ConfigOptions.push_back( dns_cache_file );
133
134     HostConfigurationOptionItem host_name( new HostNameOption );
135     HostOptions.push_back( host_name );
136
137     HostConfigurationOptionItem host_port( new HostPortOption );
138     HostOptions.push_back( host_port );
139
140     HostConfigurationOptionItem host_source_network_interface( new HostSourceNetworkInterfaceOption );
141     HostOptions.push_back( host_source_network_interface );
142
143     HostConfigurationOptionItem host_protocol( new HostPingProtocolOption );
144     HostOptions.push_back( host_protocol );
145
146     HostConfigurationOptionItem host_interval( new HostPingIntervalOption );
147     HostOptions.push_back( host_interval );
148 }
149
150 /**
151  * @brief Destructor.
152  */
153 ConfigurationOptions::~ConfigurationOptions()
154 {
155 }
156
157 /**
158  * @return The options which are common to all kinds of applications.
159  */
160 options_description ConfigurationOptions::get_generic_options() const
161 {
162     options_description options( "Generic options" );
163
164     options.add_options()
165         ( HelpCmdStr.c_str(), HelpCmdDesc.c_str() )
166     ;
167
168     BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions )
169     {
170         // Do not pass the the underlying boost::program_options::option_description
171         // object from ConfigurationOption to the
172         // boost::program_options::options_description::add() method, because it
173         // deletes the boost::program_options::option_description, causing
174         // multiple freed when ConfigurationOption try to delete it.
175         option_description option = generic_option->get_option_description();
176         shared_ptr< option_description > ptr( new option_description( option ) );
177         options.add( ptr );
178     }
179
180     return options;
181 }
182
183 /**
184  * @return The options which are specific to this application.
185  */
186 options_description ConfigurationOptions::get_configuration_options() const
187 {
188     options_description options( "Configuration" );
189
190     BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions )
191     {
192         option_description option = configuration_option->get_option_description();
193         shared_ptr< option_description > ptr( new option_description( option ) );
194         options.add( ptr );
195     }
196
197     BOOST_FOREACH( ConfigurationOptionItem host_option, HostOptions )
198     {
199         option_description option = host_option->get_option_description();
200         shared_ptr< option_description > ptr( new option_description( option ) );
201         options.add( ptr );
202     }
203
204     return options;
205 }
206
207 /**
208  * @brief Parse the options common to all kinds of applications.
209  *
210  * @param vm The input @c boost::program_options::variables_map.
211  * @param configuration The output @c Configuration filled with the parsed
212  * generic options.
213  *
214  * @return @c true if it was parsed at least one option, or @c false if there
215  * were no options available in this category.
216  */
217 bool ConfigurationOptions::parse_generic_options(
218         const variables_map& vm,
219         Configuration *configuration
220 )
221 {
222     BOOST_ASSERT(configuration != NULL);
223
224     // help
225     if ( vm.count( HelpCmdStr ) > 0 )
226     {
227         options_description generic = get_generic_options();
228         options_description config = get_configuration_options();
229
230         options_description visible_options( "Allowed options" );
231         visible_options.add( generic ).add( config );
232
233         // TODO GlobalOutput::print( help )
234         cout << visible_options << endl;
235         return true;
236     }
237
238     BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions )
239     {
240         generic_option->parse( vm, configuration );
241     }
242
243     return false;
244 }
245
246 /**
247  * @brief Parse the options specific to this application.
248  *
249  * @param vm The input @c boost::program_options::variables_map.
250  * @param configuration The output @c Configuration filled with the parsed
251  * configuration options.
252  *
253  * @return @c true if it was parsed at least one option, or @c false if there
254  * were no options available in this category.
255  */
256 bool ConfigurationOptions::parse_configuration_options(
257         const variables_map &vm,
258         Configuration *configuration
259 )
260 {
261     BOOST_ASSERT(configuration != NULL);
262
263     BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions )
264     {
265         configuration_option->parse( vm, configuration );
266     }
267
268     bool hosts_parsed = parse_hosts_options(vm, configuration);
269
270     return hosts_parsed;
271 }
272
273 /**
274  * @brief Parse the hosts section options.
275  *
276  * @param vm The input @c boost::program_options::variables_map.
277  * @param configuration The output @c Configuration filled with the parsed
278  * hosts options.
279  *
280  * @return @c true if the hosts were parsed correctly, or @c false otherwise.
281  */
282 bool ConfigurationOptions::parse_hosts_options(
283         const variables_map &vm,
284         Configuration *configuration
285 )
286 {
287     BOOST_ASSERT(configuration != NULL);
288
289     size_t host_down_limit_count = static_cast<size_t>( configuration->get_hosts_down_limit() );
290
291     BOOST_FOREACH( HostConfigurationOptionItem host_option, HostOptions )
292     {
293         bool parsed = host_option->parse( vm, configuration );
294         if ( parsed )
295         {
296             // The set_hosts_count() method is called in parse() method, that is
297             // why we must parse before check the number of host options
298             size_t hosts_parsed_count = host_option->get_hosts_count();
299             bool have_minimum_hosts = ( host_down_limit_count <= hosts_parsed_count );
300             // Ensure we have all options for each host
301             if ( !have_minimum_hosts ) {
302                 // TODO GlobalOutput::print()
303                 GlobalLogger.error() << "Could not parse configuration file." <<
304                         " Missing an entry for one of the hosts." << endl;
305                 // TODO Assume default value for a missing option
306                 return false;
307             }
308
309             BOOST_ASSERT( hosts_parsed_count >= static_cast<size_t>( host_down_limit_count ) );
310         }
311     }
312
313     return true;
314 }
315
316 /**
317  * @return which options must abort the application. Like the --version.
318  */
319 bool ConfigurationOptions::halt_on_generic_options( const variables_map &vm ) const
320 {
321     VersionOption v;
322
323     bool is_help = ( vm.count( HelpCmdStr ) > 0 );
324     bool is_version = ( vm.count( v.get_command_string() ) > 0 );
325     bool terminate_app = is_help || is_version;
326
327     return terminate_app;
328 }