1package FusionInventory::Agent::Target; 2 3use strict; 4use warnings; 5 6use English qw(-no_match_vars); 7 8use FusionInventory::Agent::Logger; 9use FusionInventory::Agent::Storage; 10 11my $errMaxDelay = 0; 12 13sub new { 14 my ($class, %params) = @_; 15 16 die "no basevardir parameter for target\n" unless $params{basevardir}; 17 18 # errMaxDelay is the maximum delay on network error. Delay on network error starts 19 # from 60, is doubled at each new failed attempt until reaching delaytime. 20 # Take the first provided delaytime for the agent lifetime 21 unless ($errMaxDelay) { 22 $errMaxDelay = $params{delaytime} || 3600; 23 } 24 25 my $self = { 26 logger => $params{logger} || 27 FusionInventory::Agent::Logger->new(), 28 maxDelay => $params{maxDelay} || 3600, 29 errMaxDelay => $errMaxDelay, 30 initialDelay => $params{delaytime}, 31 }; 32 bless $self, $class; 33 34 return $self; 35} 36 37sub _init { 38 my ($self, %params) = @_; 39 40 my $logger = $self->{logger}; 41 42 # target identity 43 $self->{id} = $params{id}; 44 45 $self->{storage} = FusionInventory::Agent::Storage->new( 46 logger => $self->{logger}, 47 directory => $params{vardir} 48 ); 49 50 # handle persistent state 51 $self->_loadState(); 52 53 $self->{nextRunDate} = $self->_computeNextRunDate() 54 if (!$self->{nextRunDate} || $self->{nextRunDate} < time-$self->getMaxDelay()); 55 56 $self->_saveState(); 57 58 $logger->debug( 59 "[target $self->{id}] Next server contact planned for " . 60 localtime($self->{nextRunDate}) 61 ); 62 63} 64 65sub getStorage { 66 my ($self) = @_; 67 68 return $self->{storage}; 69} 70 71sub setNextRunDateFromNow { 72 my ($self, $nextRunDelay) = @_; 73 74 if ($nextRunDelay) { 75 # While using nextRunDelay, we double it on each consecutive call until 76 # delay reach target defined maxDelay. This is only used on network failure. 77 $nextRunDelay = 2 * $self->{_nextrundelay} if ($self->{_nextrundelay}); 78 $nextRunDelay = $self->getMaxDelay() if ($nextRunDelay > $self->getMaxDelay()); 79 # Also limit toward the initial delaytime as it is also used to 80 # define the maximum delay on network error 81 $nextRunDelay = $self->{errMaxDelay} if ($nextRunDelay > $self->{errMaxDelay}); 82 $self->{_nextrundelay} = $nextRunDelay; 83 } 84 $self->{nextRunDate} = time + ($nextRunDelay || 0); 85 $self->_saveState(); 86 87 # Remove initialDelay to support case we are still forced to run at start 88 $self->{initialDelay} = undef; 89} 90 91sub resetNextRunDate { 92 my ($self) = @_; 93 94 $self->{_nextrundelay} = 0; 95 $self->{nextRunDate} = $self->_computeNextRunDate(); 96 $self->_saveState(); 97} 98 99sub getNextRunDate { 100 my ($self) = @_; 101 102 # Check if state file has been updated by a third party, like a script run 103 $self->_loadState() if $self->_needToReloadState(); 104 105 return $self->{nextRunDate}; 106} 107 108sub paused { 109 my ($self) = @_; 110 111 return $self->{_paused} || 0; 112} 113 114sub pause { 115 my ($self) = @_; 116 117 $self->{_paused} = 1; 118} 119 120sub continue { 121 my ($self) = @_; 122 123 delete $self->{_paused}; 124} 125 126sub getFormatedNextRunDate { 127 my ($self) = @_; 128 129 return $self->{nextRunDate} > 1 ? 130 scalar localtime($self->{nextRunDate}) : "now"; 131} 132 133sub getMaxDelay { 134 my ($self) = @_; 135 136 return $self->{maxDelay}; 137} 138 139sub setMaxDelay { 140 my ($self, $maxDelay) = @_; 141 142 $self->{maxDelay} = $maxDelay; 143 $self->_saveState(); 144} 145 146sub isType { 147 my ($self, $testtype) = @_; 148 149 return unless $testtype; 150 151 my $type = $self->getType() 152 or return; 153 154 return "$type" eq "$testtype"; 155} 156 157# compute a run date, as current date and a random delay 158# between maxDelay / 2 and maxDelay 159sub _computeNextRunDate { 160 my ($self) = @_; 161 162 my $ret; 163 if ($self->{initialDelay}) { 164 $ret = time + ($self->{initialDelay} / 2) + int rand($self->{initialDelay} / 2); 165 $self->{initialDelay} = undef; 166 } else { 167 # By default, reduce randomly the delay by 0 to 3600 seconds (1 hour max) 168 my $max_random_delay_reduc = 3600; 169 # For delays until 6 hours, reduce randomly the delay by 10 minutes for each hour: 600*(T/3600) = T/6 170 if ($self->{maxDelay} < 21600) { 171 $max_random_delay_reduc = $self->{maxDelay} / 6; 172 } elsif ($self->{maxDelay} > 86400) { 173 # Finally reduce randomly the delay by 1 hour for each 24 hours, for delay other than a day 174 $max_random_delay_reduc = $self->{maxDelay} / 24; 175 } 176 $ret = time + $self->{maxDelay} - int(rand($max_random_delay_reduc)); 177 } 178 179 return $ret; 180} 181 182sub _loadState { 183 my ($self) = @_; 184 185 my $data = $self->{storage}->restore(name => 'target'); 186 187 $self->{maxDelay} = $data->{maxDelay} if $data->{maxDelay}; 188 $self->{nextRunDate} = $data->{nextRunDate} if $data->{nextRunDate}; 189} 190 191sub _saveState { 192 my ($self) = @_; 193 194 $self->{storage}->save( 195 name => 'target', 196 data => { 197 maxDelay => $self->{maxDelay}, 198 nextRunDate => $self->{nextRunDate}, 199 } 200 ); 201} 202 203sub _needToReloadState { 204 my ($self) = @_; 205 206 # Only re-check if it's time to reload after 30 seconds 207 return if $self->{_next_reload_check} && time < $self->{_next_reload_check}; 208 209 $self->{_next_reload_check} = time+30; 210 211 return $self->{storage}->modified(name => 'target'); 212} 213 2141; 215__END__ 216 217=head1 NAME 218 219FusionInventory::Agent::Target - Abstract target 220 221=head1 DESCRIPTION 222 223This is an abstract class for execution targets. 224 225=head1 METHODS 226 227=head2 new(%params) 228 229The constructor. The following parameters are allowed, as keys of the %params 230hash: 231 232=over 233 234=item I<logger> 235 236the logger object to use 237 238=item I<maxDelay> 239 240the maximum delay before contacting the target, in seconds 241(default: 3600) 242 243=item I<basevardir> 244 245the base directory of the storage area (mandatory) 246 247=back 248 249=head2 getNextRunDate() 250 251Get nextRunDate attribute. 252 253=head2 getFormatedNextRunDate() 254 255Get nextRunDate attribute as a formated string. 256 257=head2 setNextRunDateFromNow($nextRunDelay) 258 259Set next execution date from now and after $nextRunDelay seconds (0 by default). 260 261=head2 resetNextRunDate() 262 263Set next execution date to a random value. 264 265=head2 getMaxDelay($maxDelay) 266 267Get maxDelay attribute. 268 269=head2 setMaxDelay($maxDelay) 270 271Set maxDelay attribute. 272 273=head2 getStorage() 274 275Return the storage object for this target. 276