Diferencia entre revisiones de «Cloudy plug-ins»
De Guifi.net - Wiki Hispano
(Página creada.) |
|||
(No se muestran 2 ediciones intermedias realizadas por un usuario) | |||
Línea 1: | Línea 1: | ||
− | == ¿Qué | + | == ¿Qué es un plug-in? == |
Cloudy es una distribución de Linux basada en Debian que proporciona a los usuarios una interfaz simple y cómoda para gestionar diferentes servicios que pueden usarse a través de una red comunitaria; en nuestro caso, Guifi. | Cloudy es una distribución de Linux basada en Debian que proporciona a los usuarios una interfaz simple y cómoda para gestionar diferentes servicios que pueden usarse a través de una red comunitaria; en nuestro caso, Guifi. | ||
+ | Al mismo tiempo, Cloudy ofrece una serie de herramientas que permiten a un usuario añadir un servicio de su agrado sin tener grandes conocimientos sobre redes e informática en general. Automaticamente, estos servicios se publican mediante Avahi, de manera que todo el que utilice Cloudy podrá hacer uso de estos servicios. | ||
+ | Otra manera de llamar estos servicios que se pueden poner y quitar de forma sencilla es ''plug-in''. Por tanto, entendemos por plug-in a un programa o software que un usuario quiere añadir a la distribución y que puede ser gestionado de forma simple des de la interfaz web que provee Cloudy. | ||
+ | |||
+ | == Añadir servicios a Cloudy == | ||
+ | |||
+ | === Una pequeña introducción === | ||
+ | |||
+ | Esta guía te enseñará el proceso para añadir un nuevo servicio en la distribución Cloudy. | ||
+ | |||
+ | Para serclaro y dar algunos ejemplos al mismo tiempo, integraremos un servicio bastante simple mostrando algunos trozos de código por el camino. Para seguir el tutorial con más facilidad o bien para integrar servicios más complejos, estaría bien tener algunos conocimientos de Bash<ref name="Bash">(http://www.tldp.org/LDP/Bash-Beginners-Guide/Bash-Beginners-Guide.pdf)</ref> y de PHP<ref name="PHP">(https://php.net/manual/es/index.php)</ref>. | ||
+ | |||
+ | Por simplicidad utilizaremos Pastecat<ref name="Pastecat">(https://github.com/mvdan/pastecat)</ref>. Es un buen candidato ya que: | ||
+ | |||
+ | * Es independiente y no se ''federa'' ni se comunica con otros nodos. | ||
+ | * Está hecho en Go, es facil de distribuir e instalar. | ||
+ | * No necesita archivos de configuración. | ||
+ | * No necesita muchos recursos. | ||
+ | |||
+ | === Obtener el binario === | ||
+ | |||
+ | Lo primero que hemos de investigar es como descargar e instalar el binario en Cloudy. La mayoria de software que podemos encontrar está por defecto en los paquetes de Debian, pero Pastecat no está. Si se diera el caso de que estuviera, solo tendríamos que ejecutar el comando <code>apt-get install pastecat</code> desde PHP. | ||
+ | |||
+ | Pero como este no es el caso, tendremos que obtener el binario por otro lado. Una opcion es coger el código fuente y compilarlo nosotros mismos, pero el problema de esto es que Cloudy necesitaria incluir muchas herramientas y librerias de desarrollo, y este no es el objetivo. | ||
+ | |||
+ | La mejor opción si un paquete de Debian no está disponible en los repositorios es descargar los binarios de otro lugar seguro. Podemos utilizar el servicio de ''"releases"'' de Github para ello. Las dos opciones nos dan un archivo ejecutable que tendríamos que ser capaces de ejecutar directamente sobre Cloudy. | ||
+ | |||
+ | En este caso en particular descargaremos los binarios desde el repositorio git con la siguiente linea de comandos: | ||
+ | |||
+ | <code> | ||
+ | wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386_v0.3.0 | ||
+ | </code> | ||
+ | |||
+ | Nótese que en este caso en concreto estamos descargando una versión específica para Linux con arquitectura i386. | ||
+ | |||
+ | Fijaos que tener un servicio en los paquetes de Debian tiene muchas ventajas: | ||
+ | |||
+ | * Las actualizaciones son simples y no necesitan trabajo extra desde Cloudy. | ||
+ | * El paquete está compilado para Debian de manera segura. | ||
+ | * Los archivos de ''init.d'' ya vienen por defecto. | ||
+ | * Los paquetes de Debian suelen contener correciones. | ||
+ | |||
+ | === Probarlo === | ||
+ | |||
+ | Antes de añadir un servicio deberíamos configurarlo y probarlo nosotros directamente para ver cómo funciona y que realmente funciona. También hemos de entender qué opciones de configuración o de linea de comandos necesitamos para hacer uso de este servicio en particular y como lo gestionariamos una vez este funcionando. | ||
+ | |||
+ | === Añadir el controlador === | ||
+ | |||
+ | En <code>web/plug/controllers</code> tenenmos un archivo PHP para cada servicio, llamado controlador (o 'controller' en inglés). Este archivo contiene el codigo que se ejecutará cuando se visite la página de nuestro servicio desde la interfaz de Cloudy. | ||
+ | |||
+ | ==== Añadir la función indice ==== | ||
+ | |||
+ | Lo que queremos es que nuestro servicio esté integrado en la estructura web de Cloudy. Para ello, necesitamos crear unos cuantos ''scripts'' en PHP y añadirlos a nuestro sistema. De momento crearemos dos ''scripts'': <code>pastecat.php</code> y <code>pastecat.menu.php</code>. El primer archivo es el controlador, es decir, el ''script'' que renderiza la página y tiene toda la información tal como botones o redireccionamientos. El otro es el que permite que nuestro servicio se muestre en los menus superiores desplegables de Cloudy. | ||
+ | |||
+ | El código del menú será similar a esto: | ||
+ | |||
+ | <code php> | ||
+ | <?php | ||
+ | //peerstreamer.menu.php | ||
+ | addMenu('Pastecat','pastecat','Clommunity'); | ||
+ | </code> | ||
+ | |||
+ | Por ahora, utilizaremos un ''script'' muy simple en PHP como controlador: | ||
+ | |||
+ | <code php> | ||
+ | <?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)); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | En nuestro sistema Cloudy estos archivos han de ponerse en los directorios dentro de <code>/var/local/cDistro/plug/</code>. El primero ha de ir en <code>menus</code> y el segundo en el directori <code>controllers</code>. Una vez hecho esto podemos ir a la web de nuestro Cloudy y acceder al nuevo menú Pastecat. | ||
+ | |||
+ | ==== Hacer que el controlador instale nuestro servicio ==== | ||
+ | |||
+ | Como se ha comentado anteriormente, este paso es mucho más sencillo de hacer si el servicio está entre los paquetes de Debian. Como que no es el caso de Pastecat, lo tendremos que hacer manualmente. Normalmente hacer este proceso manualmente incluye una combinación de los comandos <code>wget</code>, <code>mv</code> y <code>chmod</code>. En general, es buena idea mantener los archivos de este tipo de servicios en <code>/opt/SERVICENAME</code>. | ||
+ | |||
+ | En nuestro caso particular, lo primero que necesitamos es descargar el binario de la ''release'' de Github. Para ello utilizaremos el comando: <code>wget</code>. Dada una URL a un archivo, este comando permite descargar este archivo en nuestro sistema, i es lo que haremos con: | ||
+ | |||
+ | <code bash> | ||
+ | wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386_v0.3.0 | ||
+ | </code> | ||
+ | |||
+ | Una vez tengamos el binario en nuestra máquina, lo moveremos al directorio /opt/pastecat/. Para mover los archivos por nuestro sistema usaremos el comando <code>mv</code>. Aun así, primero tendremos que crear el directorio donde pondremos el archivo. Para ello utilizaremos <code>mkdir</code> de la siguiente manera: | ||
+ | |||
+ | <code bash> | ||
+ | mkdir -p /opt/pastecat/ | ||
+ | </code> | ||
+ | |||
+ | Una vez hayamos creado el directorio, es hora de mover el binario: | ||
+ | |||
+ | <code bash> | ||
+ | mv current_directory/pastecat_linux_386 /opt/pastecat/ | ||
+ | </code> | ||
+ | |||
+ | Donde "current_directory" es el directorio donde previamente hemos descargado el binario. Como el nombre del binario depende de la arquitectura, para simplificar el código del controlador, cambiaremos el nombre del archivo ejecutable por algo más genérico y simple: | ||
+ | |||
+ | <code bash> | ||
+ | mv /opt/pastecat/pastecat_linux_386 /opt/pastecat/pastecat | ||
+ | </code> | ||
+ | |||
+ | Ahora nuestro binario se llama <code>pastecat</code> en lugar de <code>pastecat_linux_386</code>. | ||
+ | |||
+ | Estos pasos son los requisitos mínimos para instalar un servicio que no se ofrece directamente en los repositorios oficiales de Debian. Sin embargo, de cara a un usuario final, sería una pesadilla tener que hacer todos estos comandos en una consola conectado a través de <code>ssh</code> a su dispositivo, así que lo que haremos a continuación es crear un ''script'' en Bash que será llamado más adelante a traves de la interfaz web haciendo click en un botón. | ||
+ | |||
+ | Este ''script'' es la primera versión del controlador de Pastecat. Por ahora solo incluiremos una función para instalar Pastecat en nuestro dispositivo. Más adelante incluiremos otras funciones para proveer a nuestro ''script'' de más servicios: | ||
+ | |||
+ | <code bash> | ||
+ | #!/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_v0.3.0 | ||
+ | |||
+ | # 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 | ||
+ | </code> | ||
+ | |||
+ | Podemos ver como los últimos pasos se han concentrado en una misma función, permmiténdonos instalar el software en el dispositivo de una manera mas sencilla. | ||
+ | |||
+ | ==== Hacer que el controlador utilitce Pastecat ==== | ||
+ | |||
+ | ===== Ejecutar el servicio ===== | ||
+ | |||
+ | El paso siguiente es hacer que nuestro software se pueda utilizar desde la intarfaz web. Para ello incluiremos una nueva opción en nuestra página principal de Pastecat e incluiremos una nueva función en nuestro controlador para gestionar el binario. Añadiremos un botón en el código PHP de la siguiente manera: | ||
+ | |||
+ | <code bash> | ||
+ | $page .= addButton(array('label'=>t('Create a Pastecat server'),'href'=>$staticFile.'/pastecat/publish')); | ||
+ | </code> | ||
+ | |||
+ | Ha de ir justo después del mensaje <code>Pastecat is installed</code>. A continuación se ha de implementar la función <code>publish</code> en el mismo PHP. Esta función es la responsable de llamar a la función correspondiente desde el controlador y anunciar nuestro servicio utilizando Avahi. La diferencia con esta función es que requiere un formulario para introducir datos, así que al final acabaremos teniendo dos funciones: una ''get'' i una ''post'': | ||
+ | |||
+ | <code php> | ||
+ | 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 = ""; | ||
+ | |||
+ | <nowiki>$page = "<pre>"; | ||
+ | $page .= _pcsource($description); | ||
+ | $page .= "</pre>";</nowiki> | ||
+ | |||
+ | return(array('type' => 'render','page' => $page)); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Como podemos ver en la función <code>post</code> estamos invocando otra función. El motivo de hacer esto es escribir el código de manera más simple y modular. En esta última funcion por fin llamamos al script: | ||
+ | |||
+ | <code php> | ||
+ | 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) | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Lo siguiente que hemos de hacer es crear una función <code>publish</code> en el controlador, por lo que añadiremos una nueva función al controlador básico que tenemos en la sección '''3.2'''. Primero añadiremos un nuevo paámetro llamado ''publish'', asi que la primera parte en ejecutarse del ''script'' sera: | ||
+ | |||
+ | <code bash> | ||
+ | if [ $# -lt 1 ] | ||
+ | then | ||
+ | doHelp | ||
+ | fi | ||
+ | |||
+ | case $1 in | ||
+ | "install") | ||
+ | shift | ||
+ | doInstall $@ | ||
+ | ;; | ||
+ | "publish") | ||
+ | shift | ||
+ | doServer $@ | ||
+ | ;; | ||
+ | esac | ||
+ | </code> | ||
+ | |||
+ | Como se puede ver, cuando el primer argumento del ''script'' es <code>publish</code>, desplazamos (''shift'') el resto de argumentos y llamamos a la funcion <code>doServer</code>. En esta función hemos de poner en marcha el servicio con los argumentos correspondientes, así que lo primero queharemos será poner estos parámetros en variables locales. Una vez hecho esto lo más lógico sería lanzar la aplicación directamente, pero como el ''script'' se llama con permisos de "root" (no recomendable), hemos de lanzar Pastecat como usuario <code>nobody</code>. El problema es que el usuario <code>nobody</code> no tiene casi permisos y Pastecat necesita algunos persmisos para crear directorios y archivos de texto. Para permitir que <code>nobody</code> pueda hacerlo, primero crearemos un directorio con permisos a casi todos los usuarios. Para esto, utilizaremos el comando <code>chmod</code> de nuevo. Ahora el usuario puede crear archivos y directorios dentro de este mismo directorio, y en consecuencia podemos ejecutar Pastecat. Finalmente hay que mantener el PID en una variable en caso de que lo necesitemos más adelante (que ya os adelantamos que sí lo necesitaremos): | ||
+ | |||
+ | <code bash> | ||
+ | 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 | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Fijaos que ahora estamos utilizando algunas variables globales que no estaban definidas antes, como <code>PCUSER</code> y <code>LOGFILE</code>. Estas variables tienen los siguientes valores: | ||
+ | |||
+ | |||
+ | <code bash> | ||
+ | PCPATH="/opt/pastecat/" | ||
+ | PCPROG="pastecat" | ||
+ | LOGFILE="/dev/null" | ||
+ | PCUSER="nobody | ||
+ | </code> | ||
+ | |||
+ | ===== Parar el servicio ===== | ||
+ | |||
+ | En algún momento es posible que queramos parar nuestro servicio. Para esto crearemos un botón para hacerlo. Lo primero que hacer sería crear el botón, pero si pensamos un poco veremos que antes de crearlo necesitamos una manera de saber si nuestro servicio esta ejecutándose o no. Además, también necesitamos una manera de parar nuestro servicio. Como estamos ejecutando sobre Linux, podemos parar el servicio fácilmente utilizando el comando <code>kill</code>. El problema es que para utilizar este comando primero necesitamos saber el número de identificación del proceso (PID). Por suerte, ja nos quedamos con este número cuando creamos el servidor de Pastecat; en concreto con la linea <code>pidpc=$(eval $cmd)</code>. | ||
+ | |||
+ | Ahora que tenemos todo lo que necesitamos para matar nuestro proceso vamos a ver como lo hacemos para que PHP pueda saber si el servicio está ejecutándose o no. Una manera fácil y eficiente de hacerlo es almacenando algunos datos útiles en un archivo y borrarlo cuando se pare Pastecat. De esta manera nos aseguramos que el archivo sólo existe cuando Pastecat está activo. Este archivo lo crearemos desde el controlador aádiendo las siguientes lineas justo despues de la sentencia que hemos mencionado en el párafo anterior: | ||
+ | |||
+ | <code bash> | ||
+ | # Writting server info to file | ||
+ | info="$pidpc http://$ip:$port" # Separator is space character | ||
+ | echo $info > $PCFILE | ||
+ | </code> | ||
+ | |||
+ | Donde <code>$PCFILE</code> es una variable global que contiene <code>/var/run/pc.info</code>. Fijaos | ||
+ | que el contenido del archivo sera el PID del Pastecat y la dirección completa del servidor de este. | ||
+ | |||
+ | Ahora ya tenemos una manera de saber si el servicio está activo o no, de manera que añadiremos justo a continuación el botón 'stop' en la interfaz web. Modificaremos un poco el ''script'' PHP que teniamos antes, añadiendo un anuncio indicando si Pastecat se está ejecutando o no, y dos botones más cuando éste esté ejecutándose. Así pues, nuestra función índice contendrá el siguiente codigo dentro de la condición que comprueba si Pastecat está instalado o no: | ||
+ | |||
+ | <code php> | ||
+ | <nowiki>$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'));</nowiki> | ||
+ | </code> | ||
+ | |||
+ | En este trozo de código podemos apreciar dos nuevas cosas. La priemra es una función de comprobación llamada <code>isRunning()</code>. Esta función se parece mucho a la funcion que utilizamos para comprar si Pastecat esta instalado o no: | ||
+ | |||
+ | <code php> | ||
+ | function isRunning() { | ||
+ | // Returns whether pastecat is running or not | ||
+ | global $pcfile; | ||
+ | |||
+ | return(file_exists($pcfile)); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Es tan simple como parece, solamente comprueba que el archivo creado cuando se lanza el servidor de Pastecat aun existe. Lo segundo que podemos ver nuevo en nuestro codigo es la existencia de una nueva función llamada <code>stop</code>. Esta funcion invocará otra función en el controlador que parará el servidor de Pastecat: | ||
+ | |||
+ | <code php> | ||
+ | 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')); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Para hacer que el controlador entienda esta orden tendremos que modificarla sentencia <code>case</code> y añadir la nueva función. En el <code>case</code> añadiremos lo siguiente debajo de la opción <code>install</code>: | ||
+ | |||
+ | <code bash> | ||
+ | "stop") | ||
+ | shift | ||
+ | doStop $@ | ||
+ | ;; | ||
+ | </code> | ||
+ | |||
+ | Esto llama a la función <code>doStop</code> dentro del mismo controlador. Esta función será similar a: | ||
+ | |||
+ | <code bash> | ||
+ | doStop() { | ||
+ | # Stopping pastecat server | ||
+ | pcpid=$(cat $PCFILE | cut -d' ' -f1) | ||
+ | kill $pcpid | ||
+ | |||
+ | # Removing info file | ||
+ | rm $PCFILE | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Esta función coge el PID de Pastecat del archivo que hemos creado antes, mata el proceso y finalmente borra el archivo de manera que PHP pueda detectar que Pastecat se ha parado. | ||
+ | |||
+ | Ahora podemos crear un servidor de Pastecat y pararlo. Aun así, aun hay algo que falta: hacer que el resto de usuarios puedan ver nuestro servicio. Para esto usaremos Avahi. | ||
+ | |||
+ | === Publicación de servicios Avahi === | ||
+ | |||
+ | Una de las mejores cosas de Cloudy es la caracteristica de publicar nuestros servicios con Avahi, permitiendo a otros usuarios saber qué ofrecemos y que puedan unirse a nuestro servicio. Para hacer esto primero hemos de añadir algunas lineas de código en el controlador PHP, justo debajo de la llamada al controlador en Bash para activar el servidor Pastecat. Añadiremos las siguientes lineas: | ||
+ | |||
+ | <code php> | ||
+ | $description = str_replace(' ', '', $description); | ||
+ | $temp = avahi_publish($avahi_type, $description, $port, ""); | ||
+ | $page .= ptxt($temp); | ||
+ | </code> | ||
+ | |||
+ | Aisí al final nuestra función quedará así: | ||
+ | |||
+ | <code php> | ||
+ | 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) | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Con este simple paso hemos anunciado nuestro servicio en la red de Avahi. Pero el trabajo no acaba aquí, queda aun una cosa mas por hacer: crear un botón y programarlo de manera que cuando se pulse nos redirija directamente a nuestro servidor de Pastecat. | ||
+ | |||
+ | Para hacer esto hay una carpeta llamada <code>avahi</code> dentro del directorio <code>plug</code>. Los ''scripts'' que definen la acción a llevar a cabo cuando se pulsan los botones estan en diferentes archivos dentro de este directorio. De este modo, crearemos un archivo llamado <code>pastecat.avahi.php</code> que contendrá: | ||
+ | |||
+ | <code php> | ||
+ | <?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> "); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Esto creará un botón al lado del anuncio de Avahi que apuntará a nuestro servidor. | ||
+ | |||
+ | Ahora que ya tenemos nuestro servicio anunciado, queremos que este desaparezca una vez paremos el servidor de Pastecat. Este último paso es muy simple pero importante. Consiste en unas pocas lineas de código en la función 'stop' del ''script'' PHP. Hasta ahora, esta función solo llamaba al controlador Bash y paraba Pastecat, pero ahora también parará la publicación Avavhi y mostrará un breve comentario notificando que la llamada ha funcionado: | ||
+ | |||
+ | <code php> | ||
+ | $temp = avahi_unpublish($avahi_type, $port); | ||
+ | $flash = ptxt($temp); | ||
+ | setFlash($flash); | ||
+ | </code> | ||
+ | |||
+ | Estas lineas tienen que ser añadidas justo después de la sentencia <code>execute_program_detached($cmd)</code> en la función 'stop' de PHP. | ||
+ | |||
+ | === Final === | ||
+ | |||
+ | Finalmente añadir que todos los archivos implementados en este tutorial se pueden encontrar en un repositorio Github, que aparece en el apartado de Enlaces Externos, junto a este mismo tutorial en formato Markdown (md). | ||
+ | |||
+ | |||
+ | |||
+ | == Referencias == | ||
+ | |||
+ | <references/> | ||
== Enlaces externos == | == Enlaces externos == | ||
+ | |||
https://github.com/Clommunity/Doc/tree/master/plugins/pastecat | https://github.com/Clommunity/Doc/tree/master/plugins/pastecat | ||
− | [[ | + | [[Categoría:Cloudy]] |
[[ca:Cloudy_plug-ins]] | [[ca:Cloudy_plug-ins]] | ||
[[en:Cloudy_plug-ins]] | [[en:Cloudy_plug-ins]] |
Última revisión de 18:22 3 dic 2015
Contenido
¿Qué es un plug-in?
Cloudy es una distribución de Linux basada en Debian que proporciona a los usuarios una interfaz simple y cómoda para gestionar diferentes servicios que pueden usarse a través de una red comunitaria; en nuestro caso, Guifi.
Al mismo tiempo, Cloudy ofrece una serie de herramientas que permiten a un usuario añadir un servicio de su agrado sin tener grandes conocimientos sobre redes e informática en general. Automaticamente, estos servicios se publican mediante Avahi, de manera que todo el que utilice Cloudy podrá hacer uso de estos servicios.
Otra manera de llamar estos servicios que se pueden poner y quitar de forma sencilla es plug-in. Por tanto, entendemos por plug-in a un programa o software que un usuario quiere añadir a la distribución y que puede ser gestionado de forma simple des de la interfaz web que provee Cloudy.
Añadir servicios a Cloudy
Una pequeña introducción
Esta guía te enseñará el proceso para añadir un nuevo servicio en la distribución Cloudy.
Para serclaro y dar algunos ejemplos al mismo tiempo, integraremos un servicio bastante simple mostrando algunos trozos de código por el camino. Para seguir el tutorial con más facilidad o bien para integrar servicios más complejos, estaría bien tener algunos conocimientos de Bash[1] y de PHP[2].
Por simplicidad utilizaremos Pastecat[3]. Es un buen candidato ya que:
- Es independiente y no se federa ni se comunica con otros nodos.
- Está hecho en Go, es facil de distribuir e instalar.
- No necesita archivos de configuración.
- No necesita muchos recursos.
Obtener el binario
Lo primero que hemos de investigar es como descargar e instalar el binario en Cloudy. La mayoria de software que podemos encontrar está por defecto en los paquetes de Debian, pero Pastecat no está. Si se diera el caso de que estuviera, solo tendríamos que ejecutar el comando apt-get install pastecat
desde PHP.
Pero como este no es el caso, tendremos que obtener el binario por otro lado. Una opcion es coger el código fuente y compilarlo nosotros mismos, pero el problema de esto es que Cloudy necesitaria incluir muchas herramientas y librerias de desarrollo, y este no es el objetivo.
La mejor opción si un paquete de Debian no está disponible en los repositorios es descargar los binarios de otro lugar seguro. Podemos utilizar el servicio de "releases" de Github para ello. Las dos opciones nos dan un archivo ejecutable que tendríamos que ser capaces de ejecutar directamente sobre Cloudy.
En este caso en particular descargaremos los binarios desde el repositorio git con la siguiente linea de comandos:
wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386_v0.3.0
Nótese que en este caso en concreto estamos descargando una versión específica para Linux con arquitectura i386.
Fijaos que tener un servicio en los paquetes de Debian tiene muchas ventajas:
- Las actualizaciones son simples y no necesitan trabajo extra desde Cloudy.
- El paquete está compilado para Debian de manera segura.
- Los archivos de init.d ya vienen por defecto.
- Los paquetes de Debian suelen contener correciones.
Probarlo
Antes de añadir un servicio deberíamos configurarlo y probarlo nosotros directamente para ver cómo funciona y que realmente funciona. También hemos de entender qué opciones de configuración o de linea de comandos necesitamos para hacer uso de este servicio en particular y como lo gestionariamos una vez este funcionando.
Añadir el controlador
En web/plug/controllers
tenenmos un archivo PHP para cada servicio, llamado controlador (o 'controller' en inglés). Este archivo contiene el codigo que se ejecutará cuando se visite la página de nuestro servicio desde la interfaz de Cloudy.
Añadir la función indice
Lo que queremos es que nuestro servicio esté integrado en la estructura web de Cloudy. Para ello, necesitamos crear unos cuantos scripts en PHP y añadirlos a nuestro sistema. De momento crearemos dos scripts: pastecat.php
y pastecat.menu.php
. El primer archivo es el controlador, es decir, el script que renderiza la página y tiene toda la información tal como botones o redireccionamientos. El otro es el que permite que nuestro servicio se muestre en los menus superiores desplegables de Cloudy.
El código del menú será similar a esto:
<?php //peerstreamer.menu.php addMenu('Pastecat','pastecat','Clommunity');
Por ahora, utilizaremos un script muy simple en PHP como 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 nuestro sistema Cloudy estos archivos han de ponerse en los directorios dentro de /var/local/cDistro/plug/
. El primero ha de ir en menus
y el segundo en el directori controllers
. Una vez hecho esto podemos ir a la web de nuestro Cloudy y acceder al nuevo menú Pastecat.
Hacer que el controlador instale nuestro servicio
Como se ha comentado anteriormente, este paso es mucho más sencillo de hacer si el servicio está entre los paquetes de Debian. Como que no es el caso de Pastecat, lo tendremos que hacer manualmente. Normalmente hacer este proceso manualmente incluye una combinación de los comandos wget
, mv
y chmod
. En general, es buena idea mantener los archivos de este tipo de servicios en /opt/SERVICENAME
.
En nuestro caso particular, lo primero que necesitamos es descargar el binario de la release de Github. Para ello utilizaremos el comando: wget
. Dada una URL a un archivo, este comando permite descargar este archivo en nuestro sistema, i es lo que haremos con:
wget https://github.com/mvdan/pastecat/releases/download/v0.3.0/pastecat_linux_386_v0.3.0
Una vez tengamos el binario en nuestra máquina, lo moveremos al directorio /opt/pastecat/. Para mover los archivos por nuestro sistema usaremos el comando mv
. Aun así, primero tendremos que crear el directorio donde pondremos el archivo. Para ello utilizaremos mkdir
de la siguiente manera:
mkdir -p /opt/pastecat/
Una vez hayamos creado el directorio, es hora de mover el binario:
mv current_directory/pastecat_linux_386 /opt/pastecat/
Donde "current_directory" es el directorio donde previamente hemos descargado el binario. Como el nombre del binario depende de la arquitectura, para simplificar el código del controlador, cambiaremos el nombre del archivo ejecutable por algo más genérico y simple:
mv /opt/pastecat/pastecat_linux_386 /opt/pastecat/pastecat
Ahora nuestro binario se llama pastecat
en lugar de pastecat_linux_386
.
Estos pasos son los requisitos mínimos para instalar un servicio que no se ofrece directamente en los repositorios oficiales de Debian. Sin embargo, de cara a un usuario final, sería una pesadilla tener que hacer todos estos comandos en una consola conectado a través de ssh
a su dispositivo, así que lo que haremos a continuación es crear un script en Bash que será llamado más adelante a traves de la interfaz web haciendo click en un botón.
Este script es la primera versión del controlador de Pastecat. Por ahora solo incluiremos una función para instalar Pastecat en nuestro dispositivo. Más adelante incluiremos otras funciones para proveer a nuestro script de más servicios:
#!/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_v0.3.0 # 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
Podemos ver como los últimos pasos se han concentrado en una misma función, permmiténdonos instalar el software en el dispositivo de una manera mas sencilla.
Hacer que el controlador utilitce Pastecat
Ejecutar el servicio
El paso siguiente es hacer que nuestro software se pueda utilizar desde la intarfaz web. Para ello incluiremos una nueva opción en nuestra página principal de Pastecat e incluiremos una nueva función en nuestro controlador para gestionar el binario. Añadiremos un botón en el código PHP de la siguiente manera:
$page .= addButton(array('label'=>t('Create a Pastecat server'),'href'=>$staticFile.'/pastecat/publish'));
Ha de ir justo después del mensaje Pastecat is installed
. A continuación se ha de implementar la función publish
en el mismo PHP. Esta función es la responsable de llamar a la función correspondiente desde el controlador y anunciar nuestro servicio utilizando Avahi. La diferencia con esta función es que requiere un formulario para introducir datos, así que al final acabaremos teniendo dos funciones: 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)); }
Como podemos ver en la función post
estamos invocando otra función. El motivo de hacer esto es escribir el código de manera más simple y modular. En esta última funcion por fin llamamos al 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) }
Lo siguiente que hemos de hacer es crear una función publish
en el controlador, por lo que añadiremos una nueva función al controlador básico que tenemos en la sección 3.2. Primero añadiremos un nuevo paámetro llamado publish, asi que la primera parte en ejecutarse del script sera:
if [ $# -lt 1 ] then doHelp fi case $1 in "install") shift doInstall $@ ;; "publish") shift doServer $@ ;; esac
Como se puede ver, cuando el primer argumento del script es publish
, desplazamos (shift) el resto de argumentos y llamamos a la funcion doServer
. En esta función hemos de poner en marcha el servicio con los argumentos correspondientes, así que lo primero queharemos será poner estos parámetros en variables locales. Una vez hecho esto lo más lógico sería lanzar la aplicación directamente, pero como el script se llama con permisos de "root" (no recomendable), hemos de lanzar Pastecat como usuario nobody
. El problema es que el usuario nobody
no tiene casi permisos y Pastecat necesita algunos persmisos para crear directorios y archivos de texto. Para permitir que nobody
pueda hacerlo, primero crearemos un directorio con permisos a casi todos los usuarios. Para esto, utilizaremos el comando chmod
de nuevo. Ahora el usuario puede crear archivos y directorios dentro de este mismo directorio, y en consecuencia podemos ejecutar Pastecat. Finalmente hay que mantener el PID en una variable en caso de que lo necesitemos más adelante (que ya os adelantamos que sí lo necesitaremos):
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 }
Fijaos que ahora estamos utilizando algunas variables globales que no estaban definidas antes, como PCUSER
y LOGFILE
. Estas variables tienen los siguientes valores:
PCPATH="/opt/pastecat/" PCPROG="pastecat" LOGFILE="/dev/null" PCUSER="nobody
Parar el servicio
En algún momento es posible que queramos parar nuestro servicio. Para esto crearemos un botón para hacerlo. Lo primero que hacer sería crear el botón, pero si pensamos un poco veremos que antes de crearlo necesitamos una manera de saber si nuestro servicio esta ejecutándose o no. Además, también necesitamos una manera de parar nuestro servicio. Como estamos ejecutando sobre Linux, podemos parar el servicio fácilmente utilizando el comando kill
. El problema es que para utilizar este comando primero necesitamos saber el número de identificación del proceso (PID). Por suerte, ja nos quedamos con este número cuando creamos el servidor de Pastecat; en concreto con la linea pidpc=$(eval $cmd)
.
Ahora que tenemos todo lo que necesitamos para matar nuestro proceso vamos a ver como lo hacemos para que PHP pueda saber si el servicio está ejecutándose o no. Una manera fácil y eficiente de hacerlo es almacenando algunos datos útiles en un archivo y borrarlo cuando se pare Pastecat. De esta manera nos aseguramos que el archivo sólo existe cuando Pastecat está activo. Este archivo lo crearemos desde el controlador aádiendo las siguientes lineas justo despues de la sentencia que hemos mencionado en el párafo anterior:
# Writting server info to file info="$pidpc http://$ip:$port" # Separator is space character echo $info > $PCFILE
Donde $PCFILE
es una variable global que contiene /var/run/pc.info
. Fijaos
que el contenido del archivo sera el PID del Pastecat y la dirección completa del servidor de este.
Ahora ya tenemos una manera de saber si el servicio está activo o no, de manera que añadiremos justo a continuación el botón 'stop' en la interfaz web. Modificaremos un poco el script PHP que teniamos antes, añadiendo un anuncio indicando si Pastecat se está ejecutando o no, y dos botones más cuando éste esté ejecutándose. Así pues, nuestra función índice contendrá el siguiente codigo dentro de la condición que comprueba si Pastecat está instalado 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 este trozo de código podemos apreciar dos nuevas cosas. La priemra es una función de comprobación llamada isRunning()
. Esta función se parece mucho a la funcion que utilizamos para comprar si Pastecat esta instalado o no:
function isRunning() { // Returns whether pastecat is running or not global $pcfile; return(file_exists($pcfile)); }
Es tan simple como parece, solamente comprueba que el archivo creado cuando se lanza el servidor de Pastecat aun existe. Lo segundo que podemos ver nuevo en nuestro codigo es la existencia de una nueva función llamada stop
. Esta funcion invocará otra función en el controlador que parará 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')); }
Para hacer que el controlador entienda esta orden tendremos que modificarla sentencia case
y añadir la nueva función. En el case
añadiremos lo siguiente debajo de la opción install
:
"stop") shift doStop $@ ;;
Esto llama a la función doStop
dentro del mismo controlador. Esta función será similar a:
doStop() { # Stopping pastecat server pcpid=$(cat $PCFILE | cut -d' ' -f1) kill $pcpid # Removing info file rm $PCFILE }
Esta función coge el PID de Pastecat del archivo que hemos creado antes, mata el proceso y finalmente borra el archivo de manera que PHP pueda detectar que Pastecat se ha parado.
Ahora podemos crear un servidor de Pastecat y pararlo. Aun así, aun hay algo que falta: hacer que el resto de usuarios puedan ver nuestro servicio. Para esto usaremos Avahi.
Publicación de servicios Avahi
Una de las mejores cosas de Cloudy es la caracteristica de publicar nuestros servicios con Avahi, permitiendo a otros usuarios saber qué ofrecemos y que puedan unirse a nuestro servicio. Para hacer esto primero hemos de añadir algunas lineas de código en el controlador PHP, justo debajo de la llamada al controlador en Bash para activar el servidor Pastecat. Añadiremos las siguientes lineas:
$description = str_replace(' ', , $description); $temp = avahi_publish($avahi_type, $description, $port, ""); $page .= ptxt($temp);
Aisí al final nuestra función quedará así:
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) }
Con este simple paso hemos anunciado nuestro servicio en la red de Avahi. Pero el trabajo no acaba aquí, queda aun una cosa mas por hacer: crear un botón y programarlo de manera que cuando se pulse nos redirija directamente a nuestro servidor de Pastecat.
Para hacer esto hay una carpeta llamada avahi
dentro del directorio plug
. Los scripts que definen la acción a llevar a cabo cuando se pulsan los botones estan en diferentes archivos dentro de este directorio. De este modo, crearemos un archivo llamado pastecat.avahi.php
que contendrá:
<?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> "); }
Esto creará un botón al lado del anuncio de Avahi que apuntará a nuestro servidor.
Ahora que ya tenemos nuestro servicio anunciado, queremos que este desaparezca una vez paremos el servidor de Pastecat. Este último paso es muy simple pero importante. Consiste en unas pocas lineas de código en la función 'stop' del script PHP. Hasta ahora, esta función solo llamaba al controlador Bash y paraba Pastecat, pero ahora también parará la publicación Avavhi y mostrará un breve comentario notificando que la llamada ha funcionado:
$temp = avahi_unpublish($avahi_type, $port); $flash = ptxt($temp); setFlash($flash);
Estas lineas tienen que ser añadidas justo después de la sentencia execute_program_detached($cmd)
en la función 'stop' de PHP.
Final
Finalmente añadir que todos los archivos implementados en este tutorial se pueden encontrar en un repositorio Github, que aparece en el apartado de Enlaces Externos, junto a este mismo tutorial en formato Markdown (md).
Referencias
- ↑ (http://www.tldp.org/LDP/Bash-Beginners-Guide/Bash-Beginners-Guide.pdf)
- ↑ (https://php.net/manual/es/index.php)
- ↑ (https://github.com/mvdan/pastecat)
Enlaces externos
https://github.com/Clommunity/Doc/tree/master/plugins/pastecat