texto = 'SELECT apikey FROM usuarios WHERE idusuario=1'; $rs = new Recordset; $rs->Comando = &$cmd; if (!$rs->Abrir()) return (null); $rs->Primero(); if ($rs->EOF) { return (null); } $k = $rs->campos['apikey']; $rs->Cerrar(); return $k; } /** * db_fetchCals() * @brief Retrieves calendars from the database * @return array calendars */ function db_fetchCals() { global $cnx; $tbl = array(); $cmd = CreaComando ($cnx); if (!$cmd) { die ('ACCESS_ERROR'); } $cmd->texto = 'SELECT idcalendario, description, json_text FROM calendarios'; $rs = new Recordset; $rs->Comando = &$cmd; if (!$rs->Abrir()) return ($tbl); $rs->Primero(); if ($rs->EOF) { return ($tbl); } $id = $rs->campos['idcalendario']; $desc = $rs->campos['description']; $txt = $rs->campos['json_text']; $tbl[$id] = array ( 'id' => $id, 'desc' => $desc, 'json' => json_decode($txt), ); while (1) { $rs->Siguiente(); if ($rs->EOF) { break; } $id = $rs->campos['idcalendario']; $desc = $rs->campos['description']; $txt = $rs->campos['json_text']; $tbl[$id] = array ( 'id' => $id, 'desc' => $desc, 'json' => json_decode($txt), ); } $rs->Cerrar(); return $tbl; } /** * uds_login ($auth, $username, $password) * @brief Log into UDS * @param string UDS authenticator * @param string user * @param string password * @return object response from the server, contains result, token, version and scrambler */ function uds_login ($auth, $username, $password) { global $UDS_REST_URL; $headers = []; $parameters = [ 'auth' => $auth, 'username' => $username, 'password' => $password ]; $payload = json_encode ($parameters); $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."auth/login"); curl_setopt ($ch, CURLOPT_POST, 1); curl_setopt ($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt ($ch, CURLOPT_HTTPHEADER, array ('Content-Type:application/json')); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); // https://stackoverflow.com/questions/9183178/can-php-curl-retrieve-response-headers-and-body-in-a-single-request curl_setopt ($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$headers) { $len = strlen ($header); $header = explode (':', $header, 2); if (count ($header) < 2) { // ignore invalid headers return $len; } $headers[strtolower(trim($header[0]))][] = trim($header[1]); return $len; }); // In real life you should use something like: // curl_setopt ($ch, CURLOPT_POSTFIELDS, http_build_query (array ('postvar1' => 'value1'))); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } if (preg_match ('/text\/html/', $headers['content-type'][0])) { do_log ('login API call returned HTML, not JSON'); return null; } return json_decode ($json); } /** * uds_getServiceInfo ($headers, $providerId, $serviceId) * @brief Get service information from UDS * @param array UDS headers * @param string provider id * @param string service id * @return object response from the server */ function uds_getServiceInfo ($headers, $providerId, $serviceId) { global $UDS_REST_URL; $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."providers/".$providerId."/services/".$serviceId); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } return json_decode ($json); } /** * uds_getAllServicePools ($headers) * @brief Get all service pools from UDS * @param array UDS headers * @return object response from the server */ function uds_getAllServicePools ($headers) { global $UDS_REST_URL; $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."servicespools/overview"); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } return json_decode ($json); } /** * uds_setServicePool ($headers, $servicePool) * @brief Writes service pool information to UDS * @param array UDS headers * @param object service pool details * @return object response from the server */ function uds_setServicePool ($headers, $servicePool) { global $UDS_REST_URL; $payload = json_encode ($servicePool); $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $UDS_REST_URL."servicespools/".$servicePool->id); curl_setopt ($ch, CURLOPT_POST, 1); curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt ($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } return json_decode ($json); } /** * og_getAula ($idCentro, $idAula) * @brief Gets lab information from OG * @param int building id * @param int lab id * @return object response from the server */ function og_getAula ($idCentro, $idAula) { global $OG_REST_URL; global $OG_REST_AUTH; $result = null; $url = $OG_REST_URL."ous/".$idCentro."/labs/".$idAula; $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $url); curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json', 'Authorization: '.$OG_REST_AUTH ]); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); $code = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } if ($code <= 201) { $result = json_decode ($json); } return $result; } /** * og_getClientDiskConfig ($idCentro, $idAula, $idCliente) * @brief Gets information about disks of a client from OG * @param int building id * @param int lab id * @param int client id * @return object response from the server */ function og_getClientDiskConfig ($idCentro, $idAula, $idCliente) { global $OG_REST_URL; global $OG_REST_AUTH; $result = null; $url = $OG_REST_URL."ous/".$idCentro."/labs/".$idAula."/clients/".$idCliente."/diskcfg"; $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $url); curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json', 'Authorization: '.$OG_REST_AUTH ]); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); $code = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("curl error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } if ($code <= 201) { $result = json_decode ($json); } return $result; } /** * og_aula_is_remote ($cal_id) * @brief Checks whether lab is remote right now * @param int calendar id * @return bool whether lab is remote (true) or not (false) */ function og_aula_is_remote ($cal_id) { global $cals, $tz; if (!array_key_exists ($cal_id, $cals)) { return 0; } $ruleset = $cals[$cal_id]['json']->remotepc_calendar->ruleset; if (null === $cal_id or 0 === $cal_id) { return 0; } $dt = new DateTime ('now', new DateTimeZone ($tz)); $dow = strtolower ($dt->format ('D')); // textual representation of a day, three letters, 'Mon' through 'Sun' $hour = $dt->format ('G'); // 24-hour without leading zeros $ts = $dt->format ('U'); // unix epoch // primero recorremos todas las reglas mirando solo las que tienen remote=false (ie. presencial) // si estamos fuera de todos estos rangos, es que estamos en remoto: return 1 // si estamos dentro de alguno de ellos, es que estamos en presencial: continuamos $presencial = 0; foreach ($ruleset as $r) { if (array_key_exists ('remote', $r) and $r->remote) { continue; } // remote=true, no nos interesa ahora 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 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 $presencial = 1; // si hemos llegado aqui, es que estamos en un rango presencial break; } if (0 == $presencial) { do_log ('Outside of "presencial" time slots, aula_is_remote: true'); return 1; } // si llegamos aqui, es que estamos en uno de los rangos de presencial, pero puede haber excepciones // recorremos todas las reglas mirando las que tienen remote=true // si estamos en alguno de esos rangos, return 1 foreach ($ruleset as $r) { if (!array_key_exists ('remote', $r) or !$r->remote) { continue; } // remote no está presente o es falso, no nos interesa ahora if ($ts >= $r->from_ts and $ts <= $r->to_ts) { // estamos en un rango remoto do_log ('Inside "presencial" time slots but within an exception, aula_is_remote: true'); return 1; } } do_log ('Inside "presencial" time slots and not within any exception, aula_is_remote: false'); return 0; } // {"remotepc_calendar":{"timezone":"Europe/Madrid","ruleset":[ // {"remote":false,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"from_hr":"8","to_hr":"17"}, // {"remote":true,"reason":"exc","from_ts":1709074800,"to_ts":1706569199} // ]}} function og_ordenador_cumple_criterios ($client) { if ($client->status == 'oglive' || $client->status == 'linux' || $client->status == 'windows') { return 1; } return 0; } /** * og_sondeoAula ($idCentro, $idAula, $idImagen) * @brief Gets how many clients are available for remotepc from OG * @param int building id * @param int lab id * @param int image id * @return int number of clients available for remotepc, -1 if aula is not remote or null on error */ function og_sondeoAula ($idCentro, $idAula, $idImagen) { global $OG_REST_URL; global $OG_REST_AUTH; $aula = og_getAula ($idCentro, $idAula); if (null === $aula || $aula->inremotepc != 1) { do_log ('lab is null, or not in remotepc, ignoring lab'); return -1; } if (!og_aula_is_remote ($aula->idcalendario)) { do_log ('lab is not remote, ignoring lab'); return -1; } $url = $OG_REST_URL."ous/".$idCentro."/labs/".$idAula."/clients/status"; $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $url); curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json', 'Authorization: '.$OG_REST_AUTH ]); $json = curl_exec ($ch); $curl_errno = curl_errno ($ch); $curl_error = curl_error ($ch); $code = curl_getinfo ($ch, CURLINFO_RESPONSE_CODE); curl_close ($ch); if ($curl_errno) { do_log (sprintf ("error '%s' errno '%d'", $curl_error, $curl_errno)); return null; } if ($code > 201) { return 0; } $server_output = json_decode ($json); $clientsOn = 0; foreach ($server_output as $client) { do_log (sprintf ("Evaluating client id '%s' with ip '%s' in status '%s'", $client->id, $client->ip, $client->status)); if (!og_ordenador_cumple_criterios ($client)) { do_log ('og_ordenador_cumple_criterios is false: ignoring client'); continue; } $clientDisk = og_getClientDiskConfig ($idCentro, $idAula, $client->id); if (null === $clientDisk) { do_log ('og_getClientDiskConfig returned false: ignoring client'); continue; } $part_ok = 0; for ($p = 0; $p < count ($clientDisk->diskcfg); $p++) { $part = $clientDisk->diskcfg[$p]; if (isset ($part->image) && $part->image->id == $idImagen) { $part_ok = 1; break; } } if (!$part_ok) { do_log ('Client does not have the requested image: ignoring client'); continue; } do_log ('Adding client'); $clientsOn++; } return $clientsOn; } /** * _set_lab_reserved ($idAula) * @brief Mark lab as reserved or unreserved in the OG DB * @param int lab id * @param int reserved (1) or unreserved (0) * @return bool success (true) or failure (false) */ function _set_lab_reserved ($idAula, $reserved) { global $cnx; $cmd = CreaComando ($cnx); if (!$cmd) { die ('ACCESS_ERROR'); } if ($reserved) { do_log ("reserving lab $idAula"); } else { do_log ("unreserving lab $idAula"); } $cmd->CreaParametro ('@idaula', $idAula, 1); $cmd->CreaParametro ('@reserved', $reserved, 1); $cmd->texto = 'UPDATE aulas SET remotepc_reserved=@reserved WHERE idaula=@idaula'; $resul=$cmd->Ejecutar(); return $resul; } /** * reserve_lab ($idAula) * @brief Mark lab as reserved in the OG DB * @param int lab id * @return bool success (true) or failure (false) */ function reserve_lab ($idAula) { _set_lab_reserved ($idAula, 1); } /** * unreserve_lab ($idAula) * @brief Mark lab as unreserved in the OG DB * @param int lab id * @return bool success (true) or failure (false) */ function unreserve_lab ($idAula) { _set_lab_reserved ($idAula, 0); } $OG_REST_AUTH = db_fetch_apikey(); if (null == $OG_REST_AUTH) { do_log ('Failed to fetch OG API key from the database, exiting'); exit (1); } $cals = db_fetchCals(); if (!$cals) { do_log ('No calendars, exiting'); exit (0); } $server_output = uds_login ($UDS_AUTHENTICATOR, $UDS_USER, $UDS_PASS); if (null === $server_output) { do_log ('Failed to log into UDS'); exit (1); } $headers = uds_getHeaders ($server_output->token, $server_output->scrambler); $servicePools = uds_getAllServicePools ($headers); foreach ($servicePools as $servicePool) { $providerId = $servicePool->provider_id; $serviceId = $servicePool->service_id; do_log ("Service pool with providerId '$providerId', serviceId '$serviceId'"); $service = uds_getServiceInfo ($headers, $providerId, $serviceId); if ($service === null) { do_log ('Its service is null, ignoring this service pool'); continue; } do_log (sprintf ("Its service has OU '%s', lab '%s', image '%s'", $service->ou, $service->lab, $service->image)); // Conectar con opengnsys para ver cuantos pcs hay disponibles y enviar dicho parametro $max_srvs = og_sondeoAula ($service->ou, $service->lab, $service->image); if (null === $max_srvs) { do_log ('og_sondeoAula for the OU/lab/image failed, ignoring this service pool'); continue; } elseif (-1 === $max_srvs) { unreserve_lab ($service->lab); continue; } $servicePool->osmanager_id = null; $servicePool->max_srvs = $max_srvs; $servicePool->initial_srvs = $servicePool->max_srvs; $servicePool->cache_l1_srvs = 0; $servicePool->visible = ($servicePool->max_srvs > 0); do_log (sprintf ("Initial servers '%s', max servers '%s'", $servicePool->initial_srvs, $servicePool->max_srvs)); /* if ($servicePool->initial_srvs > $servicePool->max_srvs){ $servicePool->initial_srvs = $servicePool->max_srvs; } /**/ $sp = uds_setServicePool ($headers, $servicePool); if (null === $sp) { do_log ('uds_setServicePool failed'); continue; } reserve_lab ($service->lab); 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)); } fclose ($logfd);