source: admin/WebConsole/rest/remotepc.php @ 17c28dc

918-git-images-111dconfigfileconfigure-oglivegit-imageslgromero-new-oglivemainmaint-cronmount-efivarfsmultivmmultivm-ogboot-installerogClonningEngineogboot-installer-jenkinsoglive-ipv6test-python-scriptsticket-301ticket-50ticket-50-oldticket-577ticket-585ticket-611ticket-612ticket-693ticket-700ubu24tplunification2use-local-agent-oglivevarios-instalacionwebconsole3
Last change on this file since 17c28dc was a237bd1, checked in by ramon <ramongomez@…>, 8 years ago

#708: Comprobar tipo de agente permitido para acceder a rutas REST de RemotePC.

git-svn-id: https://opengnsys.es/svn/branches/version1.1@5435 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 13.4 KB
RevLine 
[e0b6a5e]1<?php
2/**
3 * @file    remotepc.php
4 * @brief   OpenGnsys Server REST API consumed by UDS Server for Remote PC implementation.
5 * @warning All input and output messages are formatted in JSON.
6 * @note    Some ideas are based on article "How to create REST API for Android app using PHP, Slim and MySQL" by Ravi Tamada, thanx.
7 * @license GNU GPLv3+
8 * @author  Ramón M. Gómez, ETSII Univ. Sevilla
9 * @version 1.1.0 - First version
10 * @date    2017-02-01
11 */
12
13
14// REST routes.
15
16/**
[63e439a]17 * @brief    Reserve a client with an installed image and the older reservation time, then send a boot/reboot operation depending on its status.
[9ed6a67]18 * @warning  If "lab" parameter is specified, then choose a client from this lab.
[63e439a]19 * @note     Route: /ous/:ouid/images/:imageid/reserve, Method: POST
[9a39c75]20 * @param    integer ouid      OU identificator
21 * @param    integer imageid   image identificator
[63e439a]22 * @note     Input JSON message: {"labid":int_labid,"maxtime":int_hours}
[e0b6a5e]23 */
[d8b6c70]24$app->post('/ous/:ouid/images/:imageid/reserve(/)', 'validateApiKey',
[e0b6a5e]25    function($ouid, $imageid) use ($app) {
26        global $cmd;
27        global $AMBITO_ORDENADORES;
28        global $EJECUCION_COMANDO;
29        global $ACCION_INICIADA;
[232d1da]30        global $ACCION_FINALIZADA;
[e0b6a5e]31        global $ACCION_SINRESULTADO;
[232d1da]32        global $ACCION_FALLIDA;
[e0b6a5e]33        global $userid;
[6f17d76]34        $response = Array();
35        $ogagent = Array();
[e0b6a5e]36
37        // Checking parameters.
[d8b6c70]38        try {
[2f11053]39                if (!checkIds($ouid, $imageid)) {
[d8b6c70]40                        throw new Exception("Ids. must be positive integers");
41                }
42                // Reading POST parameters in JSON format.
43                $input = json_decode($app->request()->getBody());
[2f11053]44                // Default: no lab. filter.
45                if (isset($input->labid)) {
46                        $labid = $input->labid != "0" ? $input->labid : '%';
47                } else {
48                        $labid = '%';
49                }
[d8b6c70]50                $maxtime = isset($input->maxtime) ? $input->maxtime : 24;       // Default: 24 h.
[2f11053]51                $opts = Array('options' => Array('min_range' => 1));    // Check for int>0
[d8b6c70]52                if (!filter_var($labid, FILTER_VALIDATE_INT, $opts) and $labid !== '%') {
53                        throw new Exception("Lab id. must be positive integer");
54                }
55                if (!filter_var($maxtime, FILTER_VALIDATE_INT, $opts)) {
56                        throw new Exception("Time must be positive integer (in hours)");
57                }
[a237bd1]58                // Check for a valid remote agent.
59                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT']))) {
60                        throw new Exception("Bad agent: sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
61                }
[d8b6c70]62        } catch (Exception $e) {
63                // Communication error.
64                $response["message"] = $e->getMessage();
65                jsonResponse(400, $response);
66                $app->stop();
67        }
[63e439a]68        // Choose older not-reserved client with image installed and get ogAdmServer data.
[e0b6a5e]69        $cmd->texto = <<<EOD
[e7d47882]70SELECT adm.idadministradorcentro, entornos.ipserveradm, entornos.portserveradm,
[d8b6c70]71       ordenadores.idordenador, ordenadores.nombreordenador, ordenadores.ip,
72       ordenadores.mac, ordenadores.agentkey, ordenadores_particiones.numdisk,
[2f11053]73       ordenadores_particiones.numpar, aulas.idaula, aulas.idcentro
[e0b6a5e]74  FROM entornos, ordenadores
75  JOIN aulas USING(idaula)
[e7d47882]76 RIGHT JOIN administradores_centros AS adm USING(idcentro)
[e0b6a5e]77 RIGHT JOIN usuarios USING(idusuario)
78 RIGHT JOIN ordenadores_particiones USING(idordenador)
79 RIGHT JOIN imagenes USING(idimagen)
[6f17d76]80  LEFT JOIN remotepc ON remotepc.id=ordenadores.idordenador
[e7d47882]81 WHERE adm.idadministradorcentro = '$userid'
[9a39c75]82   AND aulas.idcentro = '$ouid' AND aulas.idaula LIKE '$labid' AND aulas.inremotepc = 1
83   AND imagenes.idimagen = '$imageid' AND imagenes.inremotepc = 1
[35a63b6]84   AND (remotepc.reserved < NOW() OR ISNULL(reserved))
[63e439a]85 ORDER BY remotepc.reserved ASC LIMIT 1;
[e0b6a5e]86EOD;
87        $rs=new Recordset;
88        $rs->Comando=&$cmd;
89        if (!$rs->Abrir()) return(false);       // Error opening recordset.
[e7d47882]90        // Check if user is admin and client exists.
[e0b6a5e]91        $rs->Primero();
[e7d47882]92        if (checkAdmin($rs->campos["idadministradorcentro"]) and checkParameter($rs->campos["idordenador"])) {
[2f11053]93                // Read query data.
94                $serverip = $rs->campos["ipserveradm"];
95                $serverport = $rs->campos["portserveradm"];
96                $clntid = $rs->campos["idordenador"];
97                $clntname = $rs->campos["nombreordenador"];
98                $clntip = $rs->campos["ip"];
99                $clntmac = $rs->campos["mac"];
100                $agentkey = $rs->campos["agentkey"];
101                $disk = $rs->campos["numdisk"];
102                $part = $rs->campos["numpar"];
103                $labid = $rs->campos["idaula"];
104                $ouid = $rs->campos["idcentro"];
105                // Check client's status.
106                $ogagent[$clntip]['url'] = "https://$clntip:8000/opengnsys/status";
107                $result = multiRequest($ogagent);
108                if (empty($result[$clntip]['data'])) {
109                        // Client is off, send a boot command to ogAdmServer.
110                        // TODO: if client is busy?????
111                        $reqframe = "nfn=Arrancar\r".
112                                    "ido=$clntid\r".
113                                    "iph=$clntip\r".
114                                    "mac=$clntmac\r".
115                                    "mar=1\r";
116                        sendCommand($serverip, $serverport, $reqframe, $values);
117                } else {
118                        // Client is on, send a reboot command to its OGAgent.
119                        $ogagent[$clntip]['url'] = "https://$clntip:8000/opengnsys/reboot";
120                        $ogagent[$clntip]['header'] = Array("Authorization: ".$agentkey);
[6f17d76]121                        $result = multiRequest($ogagent);
[2f11053]122                        // ... (check response)
123                        //if ($result[$clntip]['code'] != 200) {
124                        // ...
125                }
126                // DB Transaction: mark choosed client as reserved and
127                // create an init session command into client's actions queue.
128                $cmd->texto = "START TRANSACTION;";
129                $cmd->Ejecutar();
130                $timestamp = time();
131                $cmd->texto = <<<EOD
[e0b6a5e]132INSERT INTO remotepc
[d8b6c70]133   SET id='$clntid', reserved=NOW() + INTERVAL $maxtime HOUR, urllogin=NULL, urllogout=NULL
[6f17d76]134    ON DUPLICATE KEY UPDATE
[e0b6a5e]135       id=VALUES(id), reserved=VALUES(reserved),
[6f17d76]136       urllogin=VALUES(urllogin), urllogout=VALUES(urllogout);
137EOD;
[2f11053]138                $t1 = $cmd->Ejecutar();
139                $cmd->texto = <<<EOD
[e0b6a5e]140INSERT INTO acciones
141   SET tipoaccion=$EJECUCION_COMANDO,
142       idtipoaccion=9,
143       idcomando=9,
[6f17d76]144       parametros='nfn=IniciarSesion\rdsk=$disk\rpar=$part',
[e0b6a5e]145       descriaccion='RemotePC Session',
[6f17d76]146       idordenador=$clntid,
147       ip='$clntip',
148       sesion=$timestamp,
[e0b6a5e]149       fechahorareg=NOW(),
150       estado=$ACCION_INICIADA,
151       resultado=$ACCION_SINRESULTADO,
152       ambito=$AMBITO_ORDENADORES,
[6f17d76]153       idambito=$clntid,
154       restrambito='$clntip',
[e0b6a5e]155       idcentro=$ouid;
[9a39c75]156EOD;
[2f11053]157                $t2 = $cmd->Ejecutar();
[232d1da]158                // Create event to remove reservation on timeout (15 min.).
[0c9d25a]159                $timeout = "15 MINUTE";
160                $cmd->texto = <<<EOD
161CREATE EVENT e_timeout_$clntid
162       ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL $timeout DO
163       BEGIN
[232d1da]164            SET @clntid = NULL;
[0c9d25a]165            UPDATE acciones
166               SET estado = $ACCION_FINALIZADA, resultado = $ACCION_FALLIDA,
167                   descrinotificacion = 'Timeout'
[232d1da]168             WHERE descriaccion = 'RemotePC Session' AND estado = $ACCION_INICIADA
169               AND idordenador = (SELECT @clntid := '$clntid');
[0c9d25a]170            IF @clntid IS NOT NULL THEN
171               UPDATE remotepc
172                  SET reserved=NOW() - INTERVAL 1 SECOND, urllogin=NULL, urllogout=NULL
173                WHERE id = @clntid;
[232d1da]174               DELETE FROM acciones
175                WHERE idordenador = @clntid
176                  AND descriaccion = 'RemotePC Session'
177                  AND descrinotificacion = 'Timeout';
178            END IF;
[0c9d25a]179       END
180EOD;
181                $t3 = $cmd->Ejecutar();
[232d1da]182                if ($t1 and $t2 and $t3) {
[2f11053]183                        // Commit transaction on success.
184                        $cmd->texto = "COMMIT;";
185                        $cmd->Ejecutar();
186                        // Send init session command if client is booted on ogLive.
187                        $reqframe = "nfn=IniciarSesion\r".
188                                    "ido=$clntid\r".
189                                    "iph=$clntip\r".
190                                    "dsk=$disk\r".
191                                    "par=$part\r";
192                        sendCommand($serverip, $serverport, $reqframe, $values);
193                        // Compose JSON response.
194                        $response['id'] = $clntid;
195                        $response['name'] = $clntname;
196                        $response['ip'] = $clntip;
197                        $response['mac'] = $clntmac;
198                        $response['lab']['id'] = $labid;
199                        $response['ou']['id'] = $ouid;
200                        jsonResponse(200, $response);
[232d1da]201                } else {
[2f11053]202                        // Roll-back transaction on DB error.
203                        $cmd->texto = "ROLLBACK;";
204                        $cmd->Ejecutar();
[9a39c75]205                        // Error message.
[2f11053]206                        $response["message"] = "Database error";
[9a39c75]207                        jsonResponse(400, $response);
208                        $app->stop();
209                }
[9ed6a67]210        }
[e0b6a5e]211        $rs->Cerrar();
212    }
213);
214
215
216/**
217 * @brief    Store UDS server URLs to resend some events recieved from OGAgent.
218 * @note     Route: /ous/:ouid/labs/:labid/clients/:clntid/events, Method: POST
219 * @param    string urlLogin   URL to redirect login notification.
220 * @param    string urlLogout  URL to redirect logout notification.
221 * @warning  Events parameters will be stored in a new "remotepc" table.
222 */
223$app->post('/ous/:ouid/labs/:labid/clients/:clntid/events', 'validateApiKey',
224    function($ouid, $labid, $clntid) use ($app) {
225        global $cmd;
226        global $userid;
[6f17d76]227        $response = Array();
[e0b6a5e]228
[d8b6c70]229        // Checking parameters.
[e0b6a5e]230        try {
[2f11053]231                if (!checkIds($ouid, $labid, $clntid)) {
[d8b6c70]232                        throw new Exception("Ids. must be positive integers");
233                }
234                // Reading JSON parameters.
[e0b6a5e]235                $input = json_decode($app->request()->getBody());
236                $urlLogin = htmlspecialchars($input->urlLogin);
237                $urlLogout = htmlspecialchars($input->urlLogout);
[d8b6c70]238                if (!filter_var($urlLogin, FILTER_VALIDATE_URL)) {
239                        throw new Exception("Must be a valid URL for login notification");
240                }
241                if (!filter_var($urlLogout, FILTER_VALIDATE_URL)) {
242                        throw new Exception("Must be a valid URL for logout notification");
243                }
[a237bd1]244                // Check for a valid remote agent.
245                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT']))) {
246                        throw new Exception("Bad agent: sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
247                }
[e0b6a5e]248        } catch (Exception $e) {
249                // Error message.
250                $response["message"] = $e->getMessage();
251                jsonResponse(400, $response);
252                $app->stop();
253        }
254
255        // Select client data for UDS compatibility.
256        $cmd->texto = <<<EOD
[e7d47882]257SELECT adm.idadministradorcentro, ordenadores.idordenador, remotepc.*
[e0b6a5e]258  FROM remotepc
259 RIGHT JOIN ordenadores ON remotepc.id=ordenadores.idordenador
260  JOIN aulas USING(idaula)
[e7d47882]261 RIGHT JOIN administradores_centros AS adm USING(idcentro)
[e0b6a5e]262 RIGHT JOIN usuarios USING(idusuario)
[e7d47882]263 WHERE adm.idadministradorcentro = '$userid'
[e0b6a5e]264   AND idcentro = '$ouid' AND aulas.idaula ='$labid'
265   AND ordenadores.idordenador = '$clntid';
266EOD;
267        $rs=new Recordset;
268        $rs->Comando=&$cmd;
269        if (!$rs->Abrir()) return(false);       // Error opening recordset.
[e7d47882]270        // Check if user is admin and client exists.
[e0b6a5e]271        $rs->Primero();
[e7d47882]272        if (checkAdmin($rs->campos["idadministradorcentro"]) and checkParameter($rs->campos["idordenador"])) {
[e0b6a5e]273                // Check if client is reserved.
[d8b6c70]274                if (! is_null($rs->campos["reserved"])) {
[9a39c75]275                        // Updating DB if client is reserved.
[d7352ab]276                        $cmd->CreaParametro("@urllogin", $urlLogin, 0);
277                        $cmd->CreaParametro("@urllogout", $urlLogout, 0);
[e0b6a5e]278                        $cmd->texto = <<<EOD
[63e439a]279UPDATE remotepc
280   SET urllogin=@urllogin, urllogout=@urllogout
281 WHERE id='$clntid';
[9a39c75]282EOD;
[d7352ab]283                        if ($cmd->Ejecutar()) {
284                                // Confirm operation.
285                                jsonResponse(200, "");
286                        } else {
287                                // Error message.
288                                $response["message"] = "Database error";
289                                jsonResponse(400, $response);
290                                $app->stop();
291                        }
[e0b6a5e]292                } else {
293                        // Error message.
[9a39c75]294                        $response["message"] = "Client is not reserved";
[e0b6a5e]295                        jsonResponse(400, $response);
296                        $app->stop();
297                }
298        }
299        $rs->Cerrar();
300    }
301);
302
303
304$app->post('/ous/:ouid/labs/:labid/clients/:clntid/session', 'validateApiKey',
305    function($ouid, $imageid) use ($app) {
306    }
307);
308
309
[9a39c75]310$app->delete('/ous/:ouid/labs/:labid/clients/:clntid/unreserve', 'validateApiKey',
[9ed6a67]311    function($ouid, $labid, $clntid) {
[e0b6a5e]312        global $cmd;
313        global $userid;
[d7352ab]314        global $ACCION_INICIADA;
[9ed6a67]315        $response = Array();
316        $ogagent = Array();
[e0b6a5e]317
[9ed6a67]318        // Checking parameters.
[d8b6c70]319        try {
[2f11053]320                if (!checkIds($ouid, $labid, $clntid)) {
[d8b6c70]321                        throw new Exception("Ids. must be positive integers");
322                }
[a237bd1]323                // Check for a valid remote agent.
324                if (empty(preg_match('/^python-requests\//', $_SERVER['HTTP_USER_AGENT']))) {
325                        throw new Exception("Bad agent: sender=".$_SERVER['REMOTE_ADDR'].", agent=".$_SERVER['HTTP_USER_AGENT']);
326                }
[d8b6c70]327        } catch (Exception $e) {
328                // Error message.
329                $response["message"] = $e->getMessage();
330                jsonResponse(400, $response);
331                $app->stop();
332        }
333
[9ed6a67]334        // Select client data for UDS compatibility.
335        $cmd->texto = <<<EOD
[e7d47882]336SELECT adm.idadministradorcentro, ordenadores.idordenador, ordenadores.ip, ordenadores.agentkey, remotepc.reserved
[9ed6a67]337  FROM remotepc
338 RIGHT JOIN ordenadores ON remotepc.id=ordenadores.idordenador
339  JOIN aulas USING(idaula)
[e7d47882]340 RIGHT JOIN administradores_centros AS adm USING(idcentro)
[9ed6a67]341 RIGHT JOIN usuarios USING(idusuario)
[e7d47882]342 WHERE adm.idadministradorcentro = '$userid'
[9ed6a67]343   AND idcentro = '$ouid' AND aulas.idaula ='$labid'
344   AND ordenadores.idordenador = '$clntid';
345EOD;
346        $rs=new Recordset;
347        $rs->Comando=&$cmd;
348        if (!$rs->Abrir()) return(false);       // Error opening recordset.
[e7d47882]349        // Check if user is admin and client exists.
[9ed6a67]350        $rs->Primero();
[e7d47882]351        if (checkAdmin($rs->campos["idadministradorcentro"]) and checkParameter($rs->campos["idordenador"])) {
[9ed6a67]352                // Check if client is reserved.
[d8b6c70]353                if (! is_null($rs->campos["reserved"])) {
[9ed6a67]354                        // Read query data.
[40db2a3]355                        $clntip = $rs->campos["ip"];
[9ed6a67]356                        $agentkey = $rs->campos["agentkey"];
[63e439a]357                        // DB Transaction: set reservation time to the past and
[9ed6a67]358                        // remove pending boot commands from client's actions queue.
359                        $cmd->texto = "START TRANSACTION;";
360                        $cmd->Ejecutar();
361                        $cmd->texto = <<<EOD
362UPDATE remotepc
[63e439a]363   SET reserved=NOW() - INTERVAL 1 SECOND, urllogin=NULL, urllogout=NULL
[9ed6a67]364 WHERE id='$clntid';
365EOD;
366                        $cmd->Ejecutar();
367                        $cmd->texto = <<<EOD
368DELETE FROM acciones
369 WHERE idordenador = '$clntid'
[35a63b6]370   AND descriaccion = 'RemotePC Session';
[9ed6a67]371EOD;
372                        $cmd->Ejecutar();
373                        $cmd->texto = "COMMIT;";
374                        $cmd->Ejecutar();
375                        // Send a poweroff command to client's OGAgent.
376                        $ogagent[$clntip]['url'] = "https://$clntip:8000/opengnsys/poweroff";
377                        $ogagent[$clntip]['header'] = Array("Authorization: ".$agentkey);
378                        $result = multiRequest($ogagent);
379                        // ... (check response)
[357352b]380                        //if ($result[$clntip]['code'] != 200) {
[9ed6a67]381                        // ...
382                        // Confirm operation.
383                        jsonResponse(200, "");
384                } else {
385                        // Error message.
386                        $response["message"] = "Client is not reserved";
387                        jsonResponse(400, $response);
388                }
389        }
390        $rs->Cerrar();
[e0b6a5e]391    }
392);
393
394?>
Note: See TracBrowser for help on using the repository browser.