English   Español  

Cloudy plug-ins: Diferència entre les revisions

De Guifi.net - Wiki Català

Línia 54: Línia 54:
 
En <code>web/plug/controllers</code> tenim un fitxer PHP per cada servei, anomenat controlador (o 'controller' en anglès). Aquest fitxer conté el codi que s'executarà quan es visiti la pàgina del nostre servei des de la interfície web de Cloudy.
 
En <code>web/plug/controllers</code> tenim un fitxer PHP per cada servei, anomenat controlador (o 'controller' en anglès). Aquest fitxer conté el codi que s'executarà quan es visiti la pàgina del nostre servei des de la interfície web de Cloudy.
  
==== Afegint la funció índex ====
+
==== Afegir la funció índex ====
  
 
El que volem fer és que el nostre servei estigui integrat en l'estructura web de Cloudy. Per fer això, necessitem crear uns quants ''scripts'' en PHP i afegir-los al nostre dispositiu. De moment necessitarem crear dos ''scripts'': <code>pastecat.php</code> i <code>pastecat.menu.php</code>. El primer fitxer és el controlador, és a dir, l'''script'' que renderitza la pàgina i té tota la informació tal com botons o redireccionaments. L'altre és el que permet que el nostre servei es mostri en els menus superiors desplegables de Cloudy.
 
El que volem fer és que el nostre servei estigui integrat en l'estructura web de Cloudy. Per fer això, necessitem crear uns quants ''scripts'' en PHP i afegir-los al nostre dispositiu. De moment necessitarem crear dos ''scripts'': <code>pastecat.php</code> i <code>pastecat.menu.php</code>. El primer fitxer és el controlador, és a dir, l'''script'' que renderitza la pàgina i té tota la informació tal com botons o redireccionaments. L'altre és el que permet que el nostre servei es mostri en els menus superiors desplegables de Cloudy.
Línia 161: Línia 161:
 
Podem veure com els últims passos s'han concentrat dins d'una mateixa funció, permetent-nos instal·lar el software en el dispositiu d'una forma més senzilla.
 
Podem veure com els últims passos s'han concentrat dins d'una mateixa funció, permetent-nos instal·lar el software en el dispositiu d'una forma més senzilla.
  
==== Fent que el controlador utilitzi Pastecat ====
+
==== Fer que el controlador utilitzi Pastecat ====
  
 
===== Executar el servei =====
 
===== Executar el servei =====

Revisió de 15:47, 24 abr 2015

Què és un plug-in?

Cloudy és una distribució de Linux basada en Debian que dona als usuaris una interfície simple i còmoda per gestionar diferents serveis que poden ser fets servir a través d'una xarxa comunitària; en el nostre cas, Guifi.

Al mateix temps, Cloudy ofereix una sèrie d'eines que permeten a un usuari afegir un servei del seu gust sense haver de tenir grans coneixements sobre xarxes i informàtica en general. Automàticament, aquests serveis es publiquen mitjançant Avahi, de manera que tothom que disposi de Cloudy pot fer ús d'aquests servei.

Una altra manera d'anomenar aquests serveis que es poden posar i treure de forma senzilla és plug-in. Així doncs, entenem per plug-in a un programa o software que un usuari vol afegir a la distribució i que pot ser gestionat de forma simple des de la interfície web que proveeix Cloudy.


Afegir serveis a Cloudy

Una petita introducció

Aquesta guia t'ensenyarà el procés per afegir un nou servei a la distribució Cloudy.

Per tal de ser clar i donar alguns exemples al mateix temps, integrarem un servei bastant simple mostrant alguns troços de codi pel camí. Per seguir el tutorial amb més claredat, o bé per integrar serveis més complexes, fora bò que sapiguéssiu alguna cosa de Bash[1] i de PHP[2].

Per simplicitat farem servir Pastecat[3]. És un bon candidat ja que:

  • És independent i no es federa ni es comunica amb altres nodes.
  • Està fet en Go, és fàcil de distribuïr i instal·lar.
  • No necessita fitxers de configuració.
  • No necessita gaires recursos.

Obtenir el binari

El primer que hem d'investigar és com descarregar i instal·lar el binari a Cloudy. La majoria del software que podem trobat està per defecte en els paquets de Debian, però el Pastecat no hi és. Si es donés el cas que hi fós, tan sols hauriem d'executar la comanda apt-get install pastecat des de PHP.

Però com que aquest no és el cas, haurem de treure el binari d'algun altre lloc. Una opció és agafar el codi font i compilarl-lo nosaltres mateixos, però el problema d'això és que Cloudy necessitaría incloure moltes eines i llibreries per compil·lar, i aquest no és l'objectiu.

La millor opció si un paquet de Debian no està disponible en els repositoris, és descarregar els binaris des d'algun lloc segur. Podem fer servir el servei de "releases" de Github per això. Les dues opcions ens deixen amb un fitxer executable que hauriem de ser capaços de córrer directe sobre Cloudy.

En aquest cas en particular descarregarem els binaris des del repositori git amb la següent línia de comandes:

   wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386

Noteu que en aquest cas en concret estem descarregant una versió específica per un Linux amb arquitectura i386.

Fixeu-vos però, que tenir el servei en els paquets de Debian té moltes avantatges:

  • Les actualitzacions són simples i no necessiten feina extra des de Cloudy.
  • El paquet està compilat per Debian d'una manera segura.
  • Els fitxer de l'init.d ja venen per defecte.
  • Els paquets de Debian solen contenir correccions.

Provar-lo

Abans d'afegir un servei hauriem de configurar-lo i provar-lo directament nosaltres mateixos per veure com funciona i que realment funciona. També hem entendre quines opcions de configuració o línies de comandes necessitarem per fer ús d'aquest servei en particular i com el gestionarem un cop estigui funcionant.

Afegir el controlador

En web/plug/controllers tenim un fitxer PHP per cada servei, anomenat controlador (o 'controller' en anglès). Aquest fitxer conté el codi que s'executarà quan es visiti la pàgina del nostre servei des de la interfície web de Cloudy.

Afegir la funció índex

El que volem fer és que el nostre servei estigui integrat en l'estructura web de Cloudy. Per fer això, necessitem crear uns quants scripts en PHP i afegir-los al nostre dispositiu. De moment necessitarem crear dos scripts: pastecat.php i pastecat.menu.php. El primer fitxer és el controlador, és a dir, l'script que renderitza la pàgina i té tota la informació tal com botons o redireccionaments. L'altre és el que permet que el nostre servei es mostri en els menus superiors desplegables de Cloudy.

El codi del menú serà quelcom semblant a això:

   <?php
   //peerstreamer.menu.php
   addMenu('Pastecat','pastecat','Clommunity');

Per ara, farem servir un script molt simple en PHP com a controlador:

   <?php
   //pastecat
   $title="Pastecat";
   
   function index(){
       global $paspath,$title;
       global $staticFile;
   
       $page=hlc(t($title));
       $page .= hl(t("Minimalist pastebin engine written in Go"),4);
       $page .= par(t("A simple and self-hosted pastebin service written in Go").' '.t("Can use a variety of storage backends").' '.t(" Designed to optionally remove pastes after a certain period of time.").' '.("If using a persistent storage backend, pastes will be kept between runs.").' '.t("This software runs the").' '."<a href='http://paste.cat'>".t("paste.cat")."</a>". t(" public service."));
       
       return(array('type' => 'render','page' => $page));
   }

En el nostre sistema Cloudy aquests fitxers han de posar-se als directoris dins de /var/local/cDistro/plug/. El primer ha d'anar dins de menus i el segon al directori controllers. Un cop haguem fet això, podem anar al web del nostre dispositiu amb Cloudy i accedir al nou menú Pastecat.

Fer que el controlador instal·li el nostre servei

Com s'ha mencionat anteriorment, aquest pas és molt més senzill de realitzar si el servei està en els paquets de Debian. Com que no és el cas del Pastecat, ho haurem de fer manualment. Normalment, fer aquest procés manualment inclou una combinació de les comandes wget, mv i chmod. En general, és bona idea mantenir els fitxers d'aquest tipus de serveis a /opt/SERVICENAME.

En el nostre cas en particular, la primera cosa que necessitem fer és descarregar el binari de la release de Github. per tal de fer això farem ús de la comanda mencionada abans: wget. Donada una URL a un fitxer, aquesta comanda en permet descarregar aquest fitxer al nostre sistema, i això és el que farem tot seguit amb:

   wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386

Una cop tinguem el binari en la nostra màquina el mourem al directori /opt/pastecat/. Per tal de moure els fitxers pel nostre sistema farem servir la comanda mv. Tot i així, primer haurem de crear el directori on posarem el fitxer. Per fer això, utilitzarem mkdir de la següent manera:

  mkdir -p /opt/pastecat/

Una vegada haguem creat el directori, és hora de moure-hi el binari:

   mv current_directory/pastecat_linux_386 /opt/pastecat/

On "current_directory" és el directori on prèviament hem descarregat el binari. Com que el nom del binari depèn de l'arquitectura, per tal de simplificar el codi del controlador, canviarem el nom del fitxer executable a quelcom més genèric i simple:

   mv /opt/pastecat/pastecat_linux_386 /opt/pastecat/pastecat

Ara el nostre binari es diu pastecat en comptes de pastecat_linux_386

Aquests passos són els mínim requerits per instal·lar un servei que no s'ofereix directament en els repositoris oficials de Debian. Nogensmenys, de cara a un usuari final, seria un malson haver de fet totes aquestes comandes en una consola connectat a través de ssh al seu dispositiu, així que el que farem tot seguit és crear un script en bash que serà cridat més endavant a través de la interfície web clicant un botó.

Aquest script és la primera versió del controlador del Pastecat. Per ara només inclourem una funció per instal·lar el Pastecat en el nostre dispositiu. Més endavant inclourem algunes altres funcions per proveïr al nostre script amb més serveis:

   #!/bin/bash
   PCPATH="/opt/pastecat/"
   
   doInstall() {
       if isInstall
       then
           echo "Pastecat is already installed."
           return
       fi
   
       # Creating directory and switching
       mkdir -p $pcpath && cd $pcpath
   
       # Getting file
       wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386
   
       # Changing name so controller can invoke it generically
       mv pastecat_linux_386 pastecat
       chmod +x pastecat
       
       cd -
   }
   
   isInstalled() {
       [ -d $pcpath ] && return 0
       return 1
   }
   
   
   case $1 in
       "install")
           shift
           doInstall $@
           ;;
   esac

Podem veure com els últims passos s'han concentrat dins d'una mateixa funció, permetent-nos instal·lar el software en el dispositiu d'una forma més senzilla.

Fer que el controlador utilitzi Pastecat

Executar el servei

El següent que volem fer és que el nostre software es pugui fer servir des de la interfície web. És per això que inclourem una nova opció a la nostra pàgina principal de Pastecat i inclourem una nova funció en el nostre controlador per gestionar el binari. Afegirem un botó en el PHP de la següent manera:

   $page .= addButton(array('label'=>t('Create a Pastecat server'),'href'=>$staticFile.'/pastecat/publish'));

Just després del missatge Pastecat is installed. El proper que cal fer és implementar la funció publish en el mateix PHP. Aquesta funció és la responsable de cridar a la funció corresponent des del controlador i anunciar el nostre servei fent servir Avahi. La diferència amb aquesta funció és que requereix un formulari per introduïr-hi dades, així que al final acabarem tenint dues funcions: una get i una post:

   function publish_get() {
       global $pcpath,$title;
       global $staticFile;
       
       $page = hlc(t($title));
       $page .= hlc(t('Publish a pastecat server'),2);
       $page .= par(t("Write the port to publish your Pastecat service"));
       $page .= createForm(array('class'=>'form-horizontal'));
       $page .= addInput('description',t('Describe this server'));
       $page .= addSubmit(array('label'=>t('Publish'),'class'=>'btn btn-primary'));
       $page .= addButton(array('label'=>t('Cancel'),'href'=>$staticFile.'/peerstreamer'));
       
       return(array('type' => 'render','page' => $page));
   }
   
   function publish_post() {
       $port = $_POST['port'];
       $description = $_POST['description'];
       $ip = "";
       
        $page = "<pre>";
        $page .= _pcsource($description);
        $page .= "</pre>";
       
       return(array('type' => 'render','page' => $page));
   }

Com podem veure en la funció post estem invocant una altra funció. La raó de fer això és escriure un codi més simple i modular. En aquesta última funció per fi cridem a l'script:

   function _pcsource($port,$description) {
       global $pcpath,$pcprogram,$title,$pcutils,$avahi_type,$port;
   
       $page = "";
       $device = getCommunityDev()['output'][0];
       $ipserver = getCommunityIP()['output'][0];
   
       if ($description == "") $description = $type;
   
       $cmd = $pcutils." publish '$port' '$description';
       execute_program_detached($cmd);
   
       $page .= t($ipserver);
       $page .= par(t('Published this server.'));
   
       $page .= addButton(array('label'=>t('Back'),'href'=>$staticFile.'/pastecat'));
   
       return($page)
   }

El proper que hem de fer és crear una funció publish en el controlador, pel que afegirem una nova funció al controlador bàsic que teniem a la secció 3.2. Primer afegirem un nou paràmetre anomenat publish, així que la primera part a exeutar-se de l'script serà:

   if [ $# -lt 1 ]
   then
       doHelp
   fi
   
   case $1 in
       "install")
           shift
           doInstall $@
           ;;
       "publish")
           shift
           doServer $@
           ;;
   esac

Com podem veure, quan el primer argument de l'script és publish, desplazamos (shift') la resta d'arguments i cridem a la funció doServer. En aquesta funció hem de posar en marxa el servei amb els arguments corresponents, així que el primer que farem serà posar aquests paràmetres en variables locals. Una vegada haguem fet això, el més lògic seria llençar l'aplicació directament, però com que l'script es crida amb permisos de "root" (i això és dolent) hem de llençar Pastecat com a usuari nobody. El problema és que l'usuari nobody no té quasi permisos i el Pastecat necessita alguns permisos per crear directoris i fitxers de text. Per permetre que nobody pugui fer aquestes coses, primer crearem un directori garantint permisos a casibé tothom. Per aconseguir això, farem servir la comanda chmod altre vegada. Ara, l'usuari pot crear fitxers i directoris dins d'aquest mateix directori, i en conseqüència, podem córrer Pastecat. Finalment, mantindre el PID en una variable en cas que el necessitem més endavant (que ja us dic que sí que el necessitarem):

   doServer() {
       # Turning machine into a server
   
       local port=${1:-""}
       local description=${2:-""}
       local ip=${3:-"0.0.0.0"}
   
       # Creating directory with nobody permissions
       mkdir -p "/var/local/pastecat"
       chmod 777 "/var/local/pastecat" && cd "/var/local/pastecat"
   
       # Running pastecat 
       cmd='su '$PCUSER' -c "{ '$PCPATH$PCPROG' -l :'$port' > '$LOGFILE' 2>&1 & }; echo \$!"'
       pidpc=$(eval $cmd)          # keeping PID for future needs...
   
       cd -
   
       # Using the PID, we could carry on process control so if the pastecat process die, we can also
       # stop the avahi process to avoid "false connections"
   
       return
   }

Fixeu-vos que ara estem fent servir algunes variables globals que no estaven definides abans, com ara PCUSER i LOGFILE. Aquestes variables tenen els següents valors:

   PCPATH="/opt/pastecat/"
   PCPROG="pastecat"
   LOGFILE="/dev/null"
   PCUSER="nobody

Aturar el servei

En algun moment és possible que vulguem aturar el nostre servei. És per això que crearem un botó per fer-ho. La primera cosa a fer sería crear el botó, però si pensem una mica, veurem que abans de crear-lo necessitem una manera de saber si el nostre servei està corrent o no. A més a més, també necessitem una manera d'aturar el nostre servei. Com que estem corrent sobre Linux, podem aconseguir aturar el servei fàcilment fent servir la comanda kill. El problema és que per fer servir aquesta comanda primer necessitem saber el número d'identificació del procés (PID). Per sort nostra, ja vam quedar-nos amb aquest número quan vam crear el servidor de Pastecat; en concret amb la línia pidpc=$(eval $cmd).

Ara que tenim tot el que necessitem per matar el nostre procés, anem a veure com ho fem perquè el PHP pugui saber si el servei està corrent o no. Una manera fàcil i eficient de fer-ho és emmagatzemant algunes dades útils en un fitxer i borrar-lo quan s'aturi el Pastecat. D'aquesta manera ens assegurem que el fitxer només existeix quan el Pastecat està actiu. Aquest fitxer el crearem des del controlador afegint les següents línies just sota la sentència que hem mencionat en el paràgraf enterior:

   # Writting server info to file
   info="$pidpc http://$ip:$port"          # Separator is space character
   echo $info > $PCFILE

On $PCFILE és una variable global que conté /var/run/pc.info. Fixeu-vos que el contingut del fitxer serà el PID del Pastecat i la direcció completa del servidor d'aquest.

Ara ja tenim una manera de saber si el servei està actiu o no, de manera que tot seguit afegirem el botó 'stop' a la interfície web. Modificarem una mica l'script PHP que teniem abans, afegint un anunci indicant si el Pastecat s'està executant o no i 2 botons més quan aquest estigui corrent. Així doncs, la nostra funció índex contindrà el següent codi dins la condició que comproba si el Pastecat està instal·lat o no:

    $page .= "<div class='alert alert-success text-center'>".t("Pastecat is installed")."</div>\n";
    if ( isRunning() ) {
        $page .= "<div class='alert alert-success text-center'>".t("Pastecat is running")."</div>\n";
        $page .= addButton(array('label'=>t('Go to server'),'href'=>'http://'. getCommunityIP()['output'][0] .':'. $port));
        $page .= addButton(array('label'=>t('Stop server'),'href'=>$staticFile.'/pastecat/stop'));
    } else  {
        $page .= "<div class='alert alert-error text-center'>".t("Pastecat is not running")."</div>\n";
    }
    $page .= addButton(array('label'=>t('Create a Pastecat server'),'href'=>$staticFile.'/pastecat/publish'));

En aquest tros de codi podem apreciar dues coses noves en el nostre codi. La primera és una funció de comprovació anomenada isRunning(). Aquesta funció s'assembla molt a la funció que feiem servir per comprovar si el Pastecat estava instal·lat o no:

   function isRunning() {
       // Returns whether pastecat is running or not
       global $pcfile;
       
       return(file_exists($pcfile));   
   }

És tant simple com sembla, només comprova que el fitxer creat quan es llença el server de Pastecat encara existeixi. La segona cosa que podem veure nova en el nostre codi és l'existència d'una nova funció anomenada stop. Aquesta funció invocarà una altra funció en el controlador que aturarà el servidor de Pastecat:

   function stop() {
       // Stops Pastecat server
       global $pcpath,$pcprogram,$title,$pcutils,$avahi_type,$port;
       
       $page = "";
       $cmd = $pcutils." stop ";
       execute_program_detached($cmd);
       
       return(array('type'=>'redirect','url'=>$staticFile.'/pastecat'));
   }

Per tal de fer que el controlador entengui aquesta ordre, haurem de modificar-ne la sentència case i afegir-hi la noca funció. En el case hi afegirem el següent sota de l'opció install:

   "stop")
       shift
       doStop $@
       ;;

Això crida a la funció doStop dins del mateix controlador. Aquesta funció serà semblant a això:

   doStop() {
       # Stopping pastecat server
       pcpid=$(cat $PCFILE | cut -d' ' -f1)
       kill $pcpid
       
       # Removing info file
       rm $PCFILE
   }

Aquesta funció agafa el PID de Pastecat del fitxer que hem creat abans, mata el procés i finalment esborra el fitxer de manera que el php pugui detectar que el Pastecat s'ha aturat.

Ara podem crear un servidor de Pastecat i aturar-lo. Tot i així, encara hi ha quelcom que manca: fer que la resta d'usuaris puguin veure el nostre servei. I és per això que utilitzarem Avahi.

Publicació de serveis Avahi

Una de les millors coses de Cloudy és la característica de publicar els nostres serveis com una publicació d'avahi, permetent als altres usuaris saber què oferim i unir-se al nostre servei. Per fer aixo, primer hem d'afegir algunes línies de codi al controlador php, just sota de la crida al controlador en bash per activar el servidor Pastecat. Afegirem les següents línies:

   $description = str_replace(' ', , $description);
   $temp = avahi_publish($avahi_type, $description, $port, "");
   $page .= ptxt($temp);

Així que al final la nostra funció quedarà així:

   function _pcsource($port,$description) {
       global $pcpath,$pcprogram,$title,$pcutils,$avahi_type;
       
       $page = "";
       $device = getCommunityDev()['output'][0];
       $ipserver = getCommunityIP()['output'][0];
       
       if ($description == "") $description = $type;
       
       $cmd = $pcutils." publish '$port' '$description'";
       execute_program_detached($cmd);
       
       $page .= t($ipserver);
       $page .= par(t('Published this server.'));
       $description = str_replace(' ', , $description);
       $temp = avahi_publish($avahi_type, $description, $port, "");
       $page .= ptxt($temp);
       
       $page .= addButton(array('label'=>t('Back'),'href'=>$staticFile.'/pastecat'));
       
       return($page)
   }

Amb aquest simple pas hem anunciat el nostre servei a la xarxa d'avahi. Tot i això la feina no acaba aquí, encara queda una cosa més a fer: crear un botó i programar-lo de manera que quan es cliqui, ens redirigeixi directament al nostre servidor de Pastecat.

Per fer això hi ha una carpeta anomenada avahi dins del directori plug. Els scripts que defineixen l'acció a dur a terme quan es cliquen els botons d'avahi estan en diferents fitxers dins d'aquest directori. D'aquesta manera crearem un fitxer anomenat pastecat.avahi.php que contindrà:

   <?php
   // plug/avahi/pastecat.avahi.php
   
   addAvahi('pastecat','fpcserver');
   
   function fpcserver($dates){
       global $staticFile;
       
       return ("<a class='btn' href='http://" .$dates['ip'] .":". $dates['port']."'>Go to server</a>  ");
   }

Això crearà un botó al costat de l'anunci d'avahi que apuntarà al nostre servidor.

Ara que ja tenim el nostre servei anunciat, volem que aquest desaparegui un cop aturem el servidor Pastecat. Aquest últim pas és molt simple però important. Consisteix en unes poques línies de codi en la funció 'stop' de l'script PHP. Fins ara, aquesta funció només cridava el controlador Bash i aturava el Pastecat, però ara també aturarà la publicació Avahi i mostrarà un breu comentari donant a conèixer que la crida ha funcionat:

   $temp = avahi_unpublish($avahi_type, $port);
   $flash = ptxt($temp);
   setFlash($flash);

Aquestes línies han de ser afegides just després de la sentència execute_program_detached($cmd) a la funció stop del php.

Final

Finalment afegir que tots els fitxers implementats durant aquest tutorial es poden trobar en un repositori GitHub que apareix a l'apartat d'Enllaços Externs, juntament amb aquest mateix tutorial en format Markdown (md).

Referències

  1. (http://www.tldp.org/LDP/Bash-Beginners-Guide/Bash-Beginners-Guide.pdf)
  2. (https://php.net/manual/es/index.php)
  3. (https://github.com/mvdan/pastecat)


Enllaços externs

https://github.com/Clommunity/Doc/tree/master/plugins/pastecat

Eines de l'usuari