source: admin/WebConsole/uds-set-service-pool.php @ 89fce9b

configure-oglivelgromero-new-oglivemainmount-efivarfsmultivmmultivm-ogboot-installerogClonningEngineoglive-ipv6test-python-scriptsticket-577ticket-585ticket-611ticket-612ticket-693ticket-700ubu24tplunification2use-local-agent-oglivevarios-instalacion
Last change on this file since 89fce9b was a401f33, checked in by Natalia Serrano <natalia.serrano@…>, 13 months ago

refs #276 refactor a function

  • Property mode set to 100644
File size: 19.4 KB
Line 
1<?php
2// ********************************************************************
3// Author: Juan Manuel Bardallo (UHU), Natalia Serrano (Qindel)
4// Description: Updates UDS with the number of available computers depending on OG's calendars and other circumstances
5// *********************************************************************
6
7include_once("./controlacceso.php");
8include_once("./includes/CreaComando.php");
9include_once("./includes/timezone.php");
10include_once("./includes/uds.php");
11include_once("./clases/AdoPhp.php");
12
13$OG_REST_URL = 'https://localhost/opengnsys/rest/';
14$logfd = fopen ('/opt/opengnsys/log/uds-set-service-pool.log', 'a');
15if (!$logfd) {
16    error_log ("Can't open '/opt/opengnsys/log/uds-set-service-pool' for appending");
17    exit (1);
18}
19
20/**
21 *         do_log ($msg)
22 * @brief  Writes to the log file
23 * @param  string  message
24 * @return int     number of bytes written, or false on failure
25 */
26function do_log ($msg) {
27    global $logfd;
28    $log_ts = date('Y/m/d h:i:s a', time());
29    return fwrite ($logfd, sprintf ("%s %s\n", $log_ts, $msg));
30}
31
32/**
33 *         uds_getHeaders ($auth_token, $scrambler)
34 * @brief  Builds set of authentication headers from a couple of UDS params
35 * @param  string  authentication token
36 * @param  string  scrambler
37 * @return array   headers
38 */
39function uds_getHeaders ($auth_token, $scrambler) {
40    $headers = [
41        'X-Auth-Token: ' . $auth_token,                  // Authentication token to access REST API of UDS -- MUST be present in all requests except login request
42        'Content-Type: ' . 'application/json',
43        'User-Agent: '   . 'UDS Test Linux Client 1.0',  // important to include "Linux" on UA to allow UDS to know OS. If not present, UDS will not know wich OS is connecting, and will not send the correct services
44        'Scrambler: '    . $scrambler,                   // This header is a cryptographic key -- MUST BE INCLUDED in all requests except login request
45    ];
46    return $headers;
47}
48
49/**
50 *         db_fetch_apikey()
51 * @brief  Retrieves API key for the first user (assumed admin) from the OG database
52 * @return string  api key
53 */
54function db_fetch_apikey() {
55    global $cnx;
56    $cmd = CreaComando ($cnx);
57    if (!$cmd) { die ('ACCESS_ERROR'); }
58
59    $cmd->texto = 'SELECT apikey FROM usuarios WHERE idusuario=1';
60    $rs = new Recordset;
61    $rs->Comando = &$cmd;
62
63    if (!$rs->Abrir()) return (null);
64
65    $rs->Primero();
66    if ($rs->EOF) { return (null); }
67
68    $k = $rs->campos['apikey'];
69    $rs->Cerrar();
70    return $k;
71}
72
73/**
74 *         db_fetchCals()
75 * @brief  Retrieves calendars from the database
76 * @return array   calendars
77 */
78function db_fetchCals() {
79    global $cnx;
80
81    $tbl = array();
82    $cmd = CreaComando ($cnx);
83    if (!$cmd) { die ('ACCESS_ERROR'); }
84
85    $cmd->texto = 'SELECT idcalendario, description, json_text FROM calendarios';
86    $rs = new Recordset;
87    $rs->Comando = &$cmd;
88
89    if (!$rs->Abrir()) return ($tbl);
90
91    $rs->Primero();
92    if ($rs->EOF) { return ($tbl); }
93
94    $id = $rs->campos['idcalendario'];
95    $desc = $rs->campos['description'];
96    $txt = $rs->campos['json_text'];
97    $tbl[$id] = array (
98        'id'   => $id,
99        'desc' => $desc,
100        'json' => json_decode($txt),
101    );
102
103    while (1) {
104        $rs->Siguiente();
105        if ($rs->EOF) { break; }
106
107        $id = $rs->campos['idcalendario'];
108        $desc = $rs->campos['description'];
109        $txt = $rs->campos['json_text'];
110        $tbl[$id] = array (
111            'id'   => $id,
112            'desc' => $desc,
113            'json' => json_decode($txt),
114        );
115    }
116
117    $rs->Cerrar();
118    return $tbl;
119}
120
121/**
122 *         uds_login ($auth, $username, $password)
123 * @brief  Log into UDS
124 * @param  string  UDS authenticator
125 * @param  string  user
126 * @param  string  password
127 * @return object  response from the server, contains result, token, version and scrambler
128 */
129function uds_login ($auth, $username, $password) {
130    global $UDS_REST_URL;
131    $headers = [];
132
133    $parameters = [
134        'auth'     => $auth,
135        'username' => $username,
136        'password' => $password
137    ];
138
139    $payload = json_encode ($parameters);
140
141    $ch = curl_init();
142    curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."auth/login");
143    curl_setopt ($ch, CURLOPT_POST, 1);
144    curl_setopt ($ch, CURLOPT_POSTFIELDS, $payload);
145    curl_setopt ($ch, CURLOPT_HTTPHEADER, array ('Content-Type:application/json'));
146    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
147    // https://stackoverflow.com/questions/9183178/can-php-curl-retrieve-response-headers-and-body-in-a-single-request
148    curl_setopt ($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$headers) {
149        $len = strlen ($header);
150        $header = explode (':', $header, 2);
151        if (count ($header) < 2) { // ignore invalid headers
152            return $len;
153        }
154        $headers[strtolower(trim($header[0]))][] = trim($header[1]);
155        return $len;
156    });
157
158    // In real life you should use something like:
159    // curl_setopt ($ch, CURLOPT_POSTFIELDS, http_build_query (array ('postvar1' => 'value1')));
160
161    $json = curl_exec ($ch);
162    $curl_errno = curl_errno ($ch);
163    $curl_error = curl_error ($ch);
164    curl_close ($ch);
165
166    if ($curl_errno) {
167        do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno));
168        return null;
169    }
170
171    if (preg_match ('/text\/html/', $headers['content-type'][0])) {
172        do_log ('login API call returned HTML, not JSON');
173        return null;
174    }
175
176    return json_decode ($json);
177}
178
179/**
180 *         uds_getServiceInfo ($headers, $providerId, $serviceId)
181 * @brief  Get service information from UDS
182 * @param  array   UDS headers
183 * @param  string  provider id
184 * @param  string  service id
185 * @return object  response from the server
186 */
187function uds_getServiceInfo ($headers, $providerId, $serviceId) {
188    global $UDS_REST_URL;
189
190    $ch = curl_init();
191    curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."providers/".$providerId."/services/".$serviceId);
192    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
193    curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers);
194
195    $json = curl_exec ($ch);
196    $curl_errno = curl_errno ($ch);
197    $curl_error = curl_error ($ch);
198    curl_close ($ch);
199
200    if ($curl_errno) {
201        do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno));
202        return null;
203    }
204
205    return json_decode ($json);
206}
207
208/**
209 *         uds_getAllServicePools ($headers)
210 * @brief  Get all service pools from UDS
211 * @param  array   UDS headers
212 * @return object  response from the server
213 */
214function uds_getAllServicePools ($headers) {
215    global $UDS_REST_URL;
216
217    $ch = curl_init();
218    curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."servicespools/overview");
219    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
220    curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers);
221
222    $json = curl_exec ($ch);
223    $curl_errno = curl_errno ($ch);
224    $curl_error = curl_error ($ch);
225    curl_close ($ch);
226
227    if ($curl_errno) {
228        do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno));
229        return null;
230    }
231
232    return json_decode ($json);
233}
234
235/**
236 *         uds_setServicePool ($headers, $servicePool)
237 * @brief  Writes service pool information to UDS
238 * @param  array   UDS headers
239 * @param  object  service pool details
240 * @return object  response from the server
241 */
242function uds_setServicePool ($headers, $servicePool) {
243    global $UDS_REST_URL;
244
245    $payload = json_encode ($servicePool);
246
247    $ch = curl_init();
248    curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."servicespools/".$servicePool->id);
249    curl_setopt ($ch, CURLOPT_POST, 1);
250    curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, "PUT");
251    curl_setopt ($ch, CURLOPT_POSTFIELDS, $payload);
252    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
253    curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers);
254
255    $json = curl_exec ($ch);
256    $curl_errno = curl_errno ($ch);
257    $curl_error = curl_error ($ch);
258    curl_close ($ch);
259
260    if ($curl_errno) {
261        do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno));
262        return null;
263    }
264
265    return json_decode ($json);
266}
267
268/**
269 *         og_getAula ($idCentro, $idAula)
270 * @brief  Gets lab information from OG
271 * @param  int     building id
272 * @param  int     lab id
273 * @return object  response from the server
274 */
275function og_getAula ($idCentro, $idAula) {
276    global $OG_REST_URL;
277    global $OG_REST_AUTH;
278
279    $result = null;
280    $url = $OG_REST_URL."ous/".$idCentro."/labs/".$idAula;
281
282    $ch = curl_init();
283    curl_setopt ($ch, CURLOPT_URL, $url);
284    curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
285    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
286    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
287    curl_setopt ($ch, CURLOPT_HTTPHEADER, [
288        'Accept: application/json',
289        'Authorization: '.$OG_REST_AUTH
290    ]);
291
292
293    $json = curl_exec ($ch);
294    $curl_errno = curl_errno ($ch);
295    $curl_error = curl_error ($ch);
296    $code = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE);
297    curl_close ($ch);
298
299    if ($curl_errno) {
300        do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno));
301        return null;
302    }
303
304    if ($code <= 201) {
305        $result = json_decode ($json);
306    }
307
308    return $result;
309}
310
311/**
312 *         og_getClientDiskConfig ($idCentro, $idAula, $idCliente)
313 * @brief  Gets information about disks of a client from OG
314 * @param  int     building id
315 * @param  int     lab id
316 * @param  int     client id
317 * @return object  response from the server
318 */
319function og_getClientDiskConfig ($idCentro, $idAula, $idCliente) {
320    global $OG_REST_URL;
321    global $OG_REST_AUTH;
322
323    $result = null;
324    $url = $OG_REST_URL."ous/".$idCentro."/labs/".$idAula."/clients/".$idCliente."/diskcfg";
325
326    $ch = curl_init();
327    curl_setopt ($ch, CURLOPT_URL, $url);
328    curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
329    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
330    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
331    curl_setopt ($ch, CURLOPT_HTTPHEADER, [
332        'Accept: application/json',
333        'Authorization: '.$OG_REST_AUTH
334    ]);
335
336    $json = curl_exec ($ch);
337    $curl_errno = curl_errno ($ch);
338    $curl_error = curl_error ($ch);
339    $code = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE);
340    curl_close ($ch);
341
342    if ($curl_errno) {
343        do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno));
344        return null;
345    }
346
347    if ($code <= 201) {
348        $result = json_decode ($json);
349    }
350
351    return $result;
352}
353
354/**
355 *         og_aula_is_remote ($cal_id)
356 * @brief  Checks whether lab is remote right now
357 * @param  int     calendar id
358 * @return bool    whether lab is remote (true) or not (false)
359 */
360function og_aula_is_remote ($cal_id) {
361    global $cals, $tz;
362
363    if (!array_key_exists ($cal_id, $cals)) { return 0; }
364    $ruleset = $cals[$cal_id]['json']->remotepc_calendar->ruleset;
365
366    if (null === $cal_id or 0 === $cal_id) {
367        return 0;
368    }
369
370    $dt = new DateTime ('now', new DateTimeZone ($tz));
371    $dow = strtolower ($dt->format ('D'));  // textual representation of a day, three letters, 'Mon' through 'Sun'
372    $hour = $dt->format ('G');              // 24-hour without leading zeros
373    $ts = $dt->format ('U');                // unix epoch
374
375    // primero recorremos todas las reglas mirando solo las que tienen remote=false (ie. presencial)
376    // si estamos fuera de todos estos rangos, es que estamos en remoto: return 1
377    // si estamos dentro de alguno de ellos, es que estamos en presencial: continuamos
378    $presencial = 0;
379    foreach ($ruleset as $r) {
380        if (array_key_exists ('remote', $r) and $r->remote) { continue; }   // remote=true, no nos interesa ahora
381        if (!array_key_exists ($dow, $r) or !$r->$dow) { continue; }        // si el día de hoy no está, o está pero es false, es que no es presencial: no nos interesa
382        if ($hour < $r->from_hr or $hour > $r->to_hr) { continue; }         // miramos las horas. Si estamos fuera del rango, es que no es presencial: no nos interesa
383        $presencial = 1;                                                    // si hemos llegado aqui, es que estamos en un rango presencial
384        break;
385    }
386
387    if (0 == $presencial) {
388        do_log ('Outside of "presencial" time slots, aula_is_remote: true');
389        return 1;
390    }
391
392    // si llegamos aqui, es que estamos en uno de los rangos de presencial, pero puede haber excepciones
393    // recorremos todas las reglas mirando las que tienen remote=true
394    // si estamos en alguno de esos rangos, return 1
395    foreach ($ruleset as $r) {
396        if (!array_key_exists ('remote', $r) or !$r->remote) { continue; }   // remote no está presente o es falso, no nos interesa ahora
397        if ($ts >= $r->from_ts and $ts <= $r->to_ts) {                       // estamos en un rango remoto
398            do_log ('Inside "presencial" time slots but within an exception, aula_is_remote: true');
399            return 1;
400        }
401    }
402
403    do_log ('Inside "presencial" time slots and not within any exception, aula_is_remote: false');
404    return 0;
405}
406// {"remotepc_calendar":{"timezone":"Europe/Madrid","ruleset":[
407//     {"remote":false,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"from_hr":"8","to_hr":"17"},
408//     {"remote":true,"reason":"exc","from_ts":1709074800,"to_ts":1706569199}
409// ]}}
410
411function og_ordenador_cumple_criterios ($client) {
412    if ($client->status == 'oglive' || $client->status == 'linux' || $client->status == 'windows') {
413        return 1;
414    }
415
416    return 0;
417}
418
419/**
420 *         og_sondeoAula ($idCentro, $idAula, $idImagen)
421 * @brief  Gets how many clients are available for remotepc from OG
422 * @param  int     building id
423 * @param  int     lab id
424 * @param  int     image id
425 * @return int     number of clients available for remotepc, -1 if aula is not remote or null on error
426 */
427function og_sondeoAula ($idCentro, $idAula, $idImagen) {
428    global $OG_REST_URL;
429    global $OG_REST_AUTH;
430
431    $aula = og_getAula ($idCentro, $idAula);
432    if (null === $aula || $aula->inremotepc != 1) {
433        do_log ('lab is null, or not in remotepc, ignoring lab');
434        return -1;
435    }
436
437    if (!og_aula_is_remote ($aula->idcalendario)) {
438        do_log ('lab is not remote, ignoring lab');
439        return -1;
440    }
441
442    $url = $OG_REST_URL."ous/".$idCentro."/labs/".$idAula."/clients/status";
443    $ch = curl_init();
444    curl_setopt ($ch, CURLOPT_URL, $url);
445    curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
446    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
447    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
448    curl_setopt ($ch, CURLOPT_HTTPHEADER, [
449        'Accept: application/json',
450        'Authorization: '.$OG_REST_AUTH
451    ]);
452
453    $json = curl_exec ($ch);
454    $curl_errno = curl_errno ($ch);
455    $curl_error = curl_error ($ch);
456    $code = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE);
457    curl_close ($ch);
458
459    if ($curl_errno) {
460        do_log (sprintf ("error '%s' errno '%d'", $curl_error, $curl_errno));
461        return null;
462    }
463
464    if ($code > 201) { return 0; }
465
466    $server_output = json_decode ($json);
467    $clientsOn = 0;
468    foreach ($server_output as $client) {
469        do_log (sprintf ("Evaluating client id '%s' with ip '%s' in status '%s'", $client->id, $client->ip, $client->status));
470        if (!og_ordenador_cumple_criterios ($client)) {
471            do_log ('og_ordenador_cumple_criterios is false: ignoring client');
472            continue;
473        }
474
475        $clientDisk = og_getClientDiskConfig ($idCentro, $idAula, $client->id);
476        if (null === $clientDisk) {
477            do_log ('og_getClientDiskConfig returned false: ignoring client');
478            continue;
479        }
480
481        $part_ok = 0;
482        for ($p = 0; $p < count ($clientDisk->diskcfg); $p++) {
483            $part = $clientDisk->diskcfg[$p];
484            if (isset ($part->image) && $part->image->id == $idImagen) {
485                $part_ok = 1;
486                break;
487            }
488        }
489        if (!$part_ok) {
490            do_log ('Client does not have the requested image: ignoring client');
491            continue;
492        }
493
494        do_log ('Adding client');
495        $clientsOn++;
496    }
497
498    return $clientsOn;
499}
500
501/**
502 *         _set_lab_reserved ($idAula)
503 * @brief  Mark lab as reserved or unreserved in the OG DB
504 * @param  int     lab id
505 * @param  int     reserved (1) or unreserved (0)
506 * @return bool    success (true) or failure (false)
507 */
508function _set_lab_reserved ($idAula, $reserved) {
509    global $cnx;
510    $cmd = CreaComando ($cnx);
511    if (!$cmd) { die ('ACCESS_ERROR'); }
512
513    if ($reserved) {
514        do_log ("reserving lab $idAula");
515    } else {
516        do_log ("unreserving lab $idAula");
517    }
518    $cmd->CreaParametro ('@idaula', $idAula, 1);
519    $cmd->CreaParametro ('@reserved', $reserved, 1);
520    $cmd->texto = 'UPDATE aulas SET remotepc_reserved=@reserved WHERE idaula=@idaula';
521    $resul=$cmd->Ejecutar();
522    $rs->Cerrar();
523
524    return $resul;
525}
526
527/**
528 *         reserve_lab ($idAula)
529 * @brief  Mark lab as reserved in the OG DB
530 * @param  int     lab id
531 * @return bool    success (true) or failure (false)
532 */
533function reserve_lab ($idAula) {
534    _set_lab_reserved ($idAula, 1);
535}
536
537/**
538 *         unreserve_lab ($idAula)
539 * @brief  Mark lab as unreserved in the OG DB
540 * @param  int     lab id
541 * @return bool    success (true) or failure (false)
542 */
543function unreserve_lab ($idAula) {
544    _set_lab_reserved ($idAula, 0);
545}
546
547
548$OG_REST_AUTH = db_fetch_apikey();
549if (null == $OG_REST_AUTH) {
550    do_log ('Failed to fetch OG API key from the database, exiting');
551    exit (1);
552}
553
554$cals = db_fetchCals();
555if (!$cals) {
556    do_log ('No calendars, exiting');
557    exit (0);
558}
559
560$server_output = uds_login ($UDS_AUTHENTICATOR, $UDS_USER, $UDS_PASS);
561if (null === $server_output) {
562    do_log ('Failed to log into UDS');
563    exit (1);
564}
565
566$headers = uds_getHeaders ($server_output->token, $server_output->scrambler);
567$servicePools = uds_getAllServicePools ($headers);
568
569foreach ($servicePools as $servicePool) {
570    $providerId = $servicePool->provider_id;
571    $serviceId = $servicePool->service_id;
572    do_log ("Service pool with providerId '$providerId', serviceId '$serviceId'");
573
574    $service = uds_getServiceInfo ($headers, $providerId, $serviceId);
575    if ($service === null) {
576        do_log ('Its service is null, ignoring this service pool');
577        continue;
578    }
579    do_log (sprintf ("Its service has OU '%s', lab '%s', image '%s'", $service->ou, $service->lab, $service->image));
580
581    // Conectar con opengnsys para ver cuantos pcs hay disponibles y enviar dicho parametro
582    $max_srvs = og_sondeoAula ($service->ou, $service->lab, $service->image);
583    if (null === $max_srvs) {
584        do_log ('og_sondeoAula for the OU/lab/image failed, ignoring this service pool');
585        continue;
586    } elseif (-1 === $max_srvs) {
587        unreserve_lab ($service->lab);
588        continue;
589    }
590    $servicePool->osmanager_id = null;
591    $servicePool->max_srvs = $max_srvs;
592    $servicePool->initial_srvs = $servicePool->max_srvs;
593    $servicePool->cache_l1_srvs = 0;
594    $servicePool->visible = ($servicePool->max_srvs > 0);
595    do_log (sprintf ("Initial servers '%s', max servers '%s'", $servicePool->initial_srvs, $servicePool->max_srvs));
596
597    /*
598    if ($servicePool->initial_srvs > $servicePool->max_srvs){
599        $servicePool->initial_srvs = $servicePool->max_srvs;
600    }
601    /**/
602    $sp = uds_setServicePool ($headers, $servicePool);
603    if (null === $sp) {
604        do_log ('uds_setServicePool failed');
605        continue;
606    }
607
608    reserve_lab ($service->lab);
609
610    do_log (sprintf ("Service pool '%s': OU id '%d', lab id '%d', image id '%d', max servers '%d', visible '%d'", $sp->name, $service->ou, $service->lab, $service->image, $sp->max_srvs, $sp->visible));
611}
612
613fclose ($logfd);
Note: See TracBrowser for help on using the repository browser.