1 | <?php |
||
2 | /* For license terms, see /license.txt */ |
||
3 | exit; |
||
4 | /** |
||
5 | * This file is a cron microclock script. |
||
6 | * It will be used as replacement of setting individual |
||
7 | * cron lines for all virtual instances. |
||
8 | * |
||
9 | * Setup this vcron to run at the smallest period possible, as |
||
10 | * it will schedule all availables vchamilos to be run as required. |
||
11 | * Note that one activaton of this cron may not always run real crons |
||
12 | * or may be run more than one cron. |
||
13 | * |
||
14 | * If used on a big system with clustering, ensure hostnames are adressed |
||
15 | * at the load balancer entry and not on physical hosts |
||
16 | * |
||
17 | * @package plugin/vchamilo |
||
18 | * @category plugins |
||
19 | * |
||
20 | * @author Valery fremaux ([email protected]) |
||
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL |
||
22 | */ |
||
23 | define('CLI_SCRIPT', true); // for chamilo imported code |
||
24 | require_once dirname(dirname(__DIR__)).'/main/inc/global.inc.php'; |
||
25 | |||
26 | global $DB; |
||
27 | $DB = new DatabaseManager(); |
||
28 | |||
29 | define('ROUND_ROBIN', 0); |
||
30 | define('LOWEST_POSSIBLE_GAP', 1); |
||
31 | |||
32 | global $VCRON; |
||
33 | |||
34 | $VCRON = new stdClass(); |
||
35 | $VCRON->ACTIVATION = 'cli'; // choose how individual cron are launched, 'cli' or 'web' |
||
36 | $VCRON->STRATEGY = ROUND_ROBIN; // choose vcron rotation mode |
||
37 | $VCRON->PERIOD = 15 * MINSECS; // used if LOWEST_POSSIBLE_GAP to setup the max gap |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
38 | $VCRON->TIMEOUT = 300; // time out for CURL call to effective cron |
||
39 | // $VCRON->TRACE = $_configuration['root_sys'].'plugin/vchamilo/log/vcrontrace.log'; // Trace file where to collect cron outputs |
||
40 | $VCRON->TRACE = '/data/log/chamilo/vcrontrace.log'; // Trace file where to collect cron outputs |
||
41 | $VCRON->TRACE_ENABLE = true; // enables tracing |
||
42 | |||
43 | if (!is_dir($_configuration['root_sys'].'plugin/vchamilo/log')) { |
||
44 | $mode = api_get_permissions_for_new_directories(); |
||
45 | mkdir($_configuration['root_sys'].'plugin/vchamilo/log', $mode, true); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * fire a cron URL using CURL. |
||
50 | */ |
||
51 | function fire_vhost_cron($vhost) |
||
52 | { |
||
53 | global $VCRON; |
||
54 | |||
55 | if ($VCRON->TRACE_ENABLE) { |
||
56 | $CRONTRACE = fopen($VCRON->TRACE, 'a'); |
||
57 | } |
||
58 | $ch = curl_init($vhost->root_web.'/main/cron/run.php'); |
||
59 | |||
60 | $http_proxy_host = api_get_setting('vchamilo_httpproxyhost', 'vchamilo'); |
||
61 | $http_proxy_port = api_get_setting('vchamilo_httpproxyport', 'vchamilo'); |
||
62 | $http_proxy_bypass = api_get_setting('vchamilo_httpproxybypass', 'vchamilo'); |
||
63 | $http_proxy_user = api_get_setting('vchamilo_httpproxyuser', 'vchamilo'); |
||
64 | $http_proxy_password = api_get_setting('vchamilo_httpproxypassword', 'vchamilo'); |
||
65 | |||
66 | curl_setopt($ch, CURLOPT_TIMEOUT, $VCRON->TIMEOUT); |
||
67 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
||
68 | curl_setopt($ch, CURLOPT_POST, true); |
||
69 | curl_setopt($ch, CURLOPT_USERAGENT, 'Chamilo'); |
||
70 | curl_setopt($ch, CURLOPT_POSTFIELDS, ''); |
||
71 | curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: text/xml charset=UTF-8"]); |
||
72 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
||
73 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); |
||
74 | |||
75 | // Check for proxy. |
||
76 | if (!empty($http_proxy_host) && !is_proxybypass($uri)) { |
||
77 | curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false); |
||
78 | |||
79 | if (empty($http_proxy_port)) { |
||
80 | echo "Using proxy $http_proxy_host\n"; |
||
81 | curl_setopt($ch, CURLOPT_PROXY, $http_proxy_host); |
||
82 | } else { |
||
83 | echo "Using proxy $http_proxy_host:$http_proxy_port\n"; |
||
84 | curl_setopt($ch, CURLOPT_PROXY, $http_proxy_host.':'.$http_proxy_port); |
||
85 | } |
||
86 | |||
87 | if (!empty($http_proxy_user) and !empty($http_proxy_password)) { |
||
88 | curl_setopt($ch, CURLOPT_PROXYUSERPWD, $http_proxy_user.':'.$http_proxy_password); |
||
89 | if (defined('CURLOPT_PROXYAUTH')) { |
||
90 | // any proxy authentication if PHP 5.1 |
||
91 | curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM); |
||
92 | } |
||
93 | } |
||
94 | } |
||
95 | |||
96 | $timestamp_send = time(); |
||
97 | $rawresponse = curl_exec($ch); |
||
98 | $timestamp_receive = time(); |
||
99 | |||
100 | if ($rawresponse === false) { |
||
101 | $error = curl_errno($ch).':'.curl_error($ch); |
||
102 | if ($VCRON->TRACE_ENABLE) { |
||
103 | if ($CRONTRACE) { |
||
104 | fputs($CRONTRACE, "VCron start on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n"); |
||
105 | fputs($CRONTRACE, "VCron Error : $error \n"); |
||
106 | fputs($CRONTRACE, "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n"); |
||
107 | fclose($CRONTRACE); |
||
108 | } |
||
109 | } |
||
110 | echo "VCron started on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n"; |
||
111 | echo "VCron Error : $error \n"; |
||
112 | echo "VCron stop on $vhost->root_web : ".api_time_to_hms($timestamp_receive)."\n#################\n\n"; |
||
113 | |||
114 | return false; |
||
115 | } |
||
116 | |||
117 | if ($VCRON->TRACE_ENABLE) { |
||
118 | if ($CRONTRACE) { |
||
119 | fputs($CRONTRACE, "VCron start on $vhost->vhostname : ".api_time_to_hms($timestamp_send)."\n"); |
||
120 | fputs($CRONTRACE, $rawresponse."\n"); |
||
121 | fputs($CRONTRACE, "VCron stop on $vhost->vhostname : ".api_time_to_hms($timestamp_receive)."\n#################\n\n"); |
||
122 | fclose($CRONTRACE); |
||
123 | } |
||
124 | } |
||
125 | echo "VCron start on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n"; |
||
126 | echo $rawresponse."\n"; |
||
127 | echo "VCron stop on $vhost->root_web : ".api_time_to_hms($timestamp_receive)."\n#################\n\n"; |
||
128 | $vhost->lastcrongap = time() - $vhost->lastcron; |
||
129 | $vhost->lastcron = $timestamp_send; |
||
130 | $vhost->croncount++; |
||
131 | |||
132 | $vhostid = $vhost->id; |
||
133 | unset($vhost->id); |
||
134 | |||
135 | Database::update('vchamilo', (array) $vhost, ['id = ?' => $vhostid]); |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * fire a cron URL using cli exec. |
||
140 | */ |
||
141 | function exec_vhost_cron($vhost) |
||
142 | { |
||
143 | global $VCRON, $DB, $_configuration; |
||
144 | |||
145 | if ($VCRON->TRACE_ENABLE) { |
||
146 | $CRONTRACE = fopen($VCRON->TRACE, 'a'); |
||
147 | } |
||
148 | |||
149 | $cmd = 'php "'.$_configuration['root_sys'].'/plugin/vchamilo/cli/cron.php" --host='.$vhost->root_web; |
||
150 | |||
151 | $timestamp_send = time(); |
||
152 | exec($cmd, $rawresponse); |
||
153 | $timestamp_receive = time(); |
||
154 | |||
155 | if ($VCRON->TRACE_ENABLE) { |
||
156 | if ($CRONTRACE) { |
||
157 | fputs($CRONTRACE, "VCron start on $vhost->root_web : $timestamp_send\n"); |
||
158 | fputs($CRONTRACE, $rawresponse."\n"); |
||
159 | fputs($CRONTRACE, "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n"); |
||
160 | fclose($CRONTRACE); |
||
161 | } |
||
162 | } |
||
163 | |||
164 | echo "VCron start on $vhost->root_web : $timestamp_send\n"; |
||
165 | echo implode("\n", $rawresponse)."\n"; |
||
166 | echo "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n"; |
||
167 | |||
168 | $vhost->lastcrongap = time() - $vhost->lastcron; |
||
169 | $vhost->lastcron = $timestamp_send; |
||
170 | $vhost->croncount++; |
||
171 | |||
172 | $DB->update_record('vchamilo', $vhost, 'id'); |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * check if $url matches anything in proxybypass list. |
||
177 | * |
||
178 | * any errors just result in the proxy being used (least bad) |
||
179 | * |
||
180 | * @global object |
||
181 | * |
||
182 | * @param string $url url to check |
||
183 | * |
||
184 | * @return bool true if we should bypass the proxy |
||
185 | */ |
||
186 | function is_proxybypass($url) |
||
187 | { |
||
188 | $http_proxy_host = api_get_setting('vchamilo_httpproxyhost', 'vchamilo'); |
||
189 | $http_proxy_port = api_get_setting('vchamilo_httpproxyport', 'vchamilo'); |
||
190 | $http_proxy_bypass = api_get_setting('vchamilo_httpproxybypass', 'vchamilo'); |
||
191 | |||
192 | // sanity check |
||
193 | if (empty($http_proxy_host) or empty($http_proxy_bypass)) { |
||
194 | return false; |
||
195 | } |
||
196 | |||
197 | // get the host part out of the url |
||
198 | if (!$host = parse_url($url, PHP_URL_HOST)) { |
||
199 | return false; |
||
200 | } |
||
201 | |||
202 | // get the possible bypass hosts into an array |
||
203 | $matches = explode(',', $http_proxy_bypass); |
||
204 | |||
205 | // check for a match |
||
206 | // (IPs need to match the left hand side and hosts the right of the url, |
||
207 | // but we can recklessly check both as there can't be a false +ve) |
||
208 | $bypass = false; |
||
209 | foreach ($matches as $match) { |
||
210 | $match = trim($match); |
||
211 | |||
212 | // try for IP match (Left side) |
||
213 | $lhs = substr($host, 0, strlen($match)); |
||
214 | if (strcasecmp($match, $lhs) == 0) { |
||
215 | return true; |
||
216 | } |
||
217 | |||
218 | // try for host match (Right side) |
||
219 | $rhs = substr($host, -strlen($match)); |
||
220 | if (strcasecmp($match, $rhs) == 0) { |
||
221 | return true; |
||
222 | } |
||
223 | } |
||
224 | |||
225 | // nothing matched. |
||
226 | return false; |
||
227 | } |
||
228 | |||
229 | // Main execution sequence |
||
230 | |||
231 | if (!$vchamilos = Database::select('*', 'vchamilo', [], 'all')) { |
||
232 | exit("Nothing to do. No Vhosts"); |
||
233 | } |
||
234 | |||
235 | $allvhosts = array_values($vchamilos); |
||
236 | |||
237 | echo "<pre>"; |
||
238 | echo "Chamilo VCron... start\n"; |
||
239 | echo "Last croned : ".api_get_setting('vchamilo_cron_lasthost', 'vchamilo')."\n"; |
||
240 | |||
241 | if ($VCRON->STRATEGY == ROUND_ROBIN) { |
||
242 | $rr = 0; |
||
243 | foreach ($allvhosts as $vhostassoc) { |
||
244 | $vhost = (object) $vhostassoc; |
||
245 | if ($rr == 1) { |
||
246 | api_set_setting('vchamilo_cron_lasthost', $vhost->id); |
||
247 | echo "Round Robin : ".$vhost->root_web."\n"; |
||
248 | if ($VCRON->ACTIVATION == 'cli') { |
||
249 | exec_vhost_cron($vhost); |
||
250 | } else { |
||
251 | fire_vhost_cron($vhost); |
||
252 | } |
||
253 | |||
254 | exit('Done.'); |
||
255 | } |
||
256 | if ($vhost->id == api_get_setting('vchamilo_cron_lasthost', 'vchamilo')) { |
||
257 | $rr = 1; // take next one |
||
258 | } |
||
259 | } |
||
260 | |||
261 | // We were at last. Loop back and take first. |
||
262 | $firsthost = (object) $allvhosts[0]; |
||
263 | api_set_setting('vchamilo_cron_lasthost', $firsthost->id, 'vchamilo'); |
||
264 | echo "Round Robin : ".$firsthost->root_web."\n"; |
||
265 | if ($VCRON->ACTIVATION == 'cli') { |
||
266 | exec_vhost_cron($firsthost); |
||
267 | } else { |
||
268 | fire_vhost_cron($firsthost); |
||
269 | } |
||
270 | } elseif ($VCRON->STRATEGY == LOWEST_POSSIBLE_GAP) { |
||
271 | // First make measurement of cron period. |
||
272 | if (api_get_setting('vcrontickperiod', 'vchamilo')) { |
||
273 | api_set_setting('vcrontime', time(), 'vchamilo'); |
||
274 | |||
275 | return; |
||
276 | } |
||
277 | api_set_setting('vcrontickperiod', time() - api_get_setting('vcrontime', 'vchamilo'), 'vchamilo'); |
||
278 | $hostsperturn = max(1, $VCRON->PERIOD / api_get_setting('vcrontickperiod', 'vchamilo') * count($allvhosts)); |
||
279 | $i = 0; |
||
280 | foreach ($allvhosts as $vhostassoc) { |
||
281 | $vhost = (object) $vhostassoc; |
||
282 | if ((time() - $vhost->lastcron) > $VCRON->PERIOD) { |
||
283 | if ($VCRON->ACTIVATION == 'cli') { |
||
284 | exec_vhost_cron($vhost); |
||
285 | } else { |
||
286 | fire_vhost_cron($vhost); |
||
287 | } |
||
288 | $i++; |
||
289 | if ($i >= $hostsperturn) { |
||
290 | return; |
||
291 | } |
||
292 | } |
||
293 | } |
||
294 | } |
||
295 |