Linux https://www.carloscarrascal.com/ es Revertir a una version anterior un paquete en Debian https://www.carloscarrascal.com/blog/revertir-una-version-anterior-un-paquete-en-debian <article data-history-node-id="39" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Revertir a una version anterior un paquete en Debian </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Sábado, Julio 14, 2018 - 22:10</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/debian" hreflang="es">Debian</a></div> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p>Una de las diversiones de utilizar la versión <a href="https://www.debian.org/releases/sid/">Sid</a> (inestable) de Debian, es actualizar paquetes. Cualquier cosa puede pasar.</p> <p>Hoy tenia un rato libre y le he dado al apt upgrade a ver que pasaba. Lo que ha pasado es que VirtualBox ha dejado de funcionar, y no arranca las máquinas virtuales, con este error:</p> <ul> <li><a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=902897">virtualbox: fails to start vm (VERR_LDRELF_RELOCATION_NOT_SUPPORTED)</a><br />  </li> </ul> <p>Después de revisar el hilo del error, parece que lo mas rápido es bajar de versión el paquete, ya que la última instalada es la <em>5.2.14-dfsg-4</em>, por lo que parece, la versión anterior (<em>5.2.14-dfsg-3</em> en este caso) parece que funciona bien.</p> <p>Así que voy a intertar explicaros como he hecho para bajar el paquete de versión, sin tener que bajar e instalar a mano el paquete, sino usando los repos de Debian.</p> <p>Primero, vamos a <a href="http://snapshot.debian.org/">snapshot.debian.org</a> y buscamos el paquete que nos da problemas, en mi caso virtualbox. Podemos usar la caja de búsqueda o rebuscar a mano por el índice, lo que os de mas morbo.</p> <p>Hay que seleccionar la versión que buscamos, y debajo del nombre del paquete vereis algo como esto:</p> <blockquote> <p>Seen in debian on 2018-07-12 14:59:27 in <a href="http://snapshot.debian.org/archive/debian/20180712T145927Z/pool/contrib/v/virtualbox/">/pool/contrib/v/virtualbox</a>. </p> </blockquote> <p>Al pinchar en el enlace, llegamos a una dirección de este tipo:</p> <ul> <li><a href="http://snapshot.debian.org/archive/debian/20180712T211510Z/pool/contrib/v/virtualbox/">http://snapshot.debian.org/archive/debian/20180712T211510Z/pool/contrib…</a></li> </ul> <p>Una vez encontrada esta URL, vamos a usarla configurando una nueva fuente para Apt:</p> <pre> cd /etc/apt/sources.list.d</pre> <p>Y creamos un nuevo archivo de fuente:</p> <pre> sudo vi virtualbox.list</pre> <p>Tenemos que usar parte de la URL de antes, sin poner la parte final. En mi caso añado la versión unstable, y el <em>contrib</em>, porque el paquete es de <em>contrib</em>. Quedaría algo así:</p> <pre> deb https://snapshot.debian.org/archive/debian/20180712T211510Z/ unstable contrib </pre> <p>Guardamos el archivo y actualizamos el <em>Apt</em> para que incluya el nuevo índice:</p> <pre> apt update</pre> <p>Una vez termine de actualizar, podemos sacar la lista de versiones disponibles del paquete que necesitamos:</p> <pre> apt-cache showpkg virtualbox</pre> <p>E instalar la que necesitemos, usando el nombre de la version en el mismo comando de <em>Apt</em>:</p> <pre> apt install virtualbox=5.2.14-dfsg-3</pre> <p>En mi caso, el paquete <em>virtualbox</em> tenía un paquete recomendado llamado <em>virtualbox-qt</em>, que <em>Apt</em> muy amablemente me indicó al tratar de instalarlo, así que decidí bajarlo de versión también por si acaso:</p> <pre> apt install virtualbox=5.2.14-dfsg-3 virtualbox-qt=5.2.14-dfsg-3 </pre> <p>Con esto se actualizaron los paquetes necesarios para esas versiones, y encima tuve la suerte de que VirtualBox volvió a funcionar perfectamente. Ahora veremos que pasa cuando salga la version siguiente (<em>5.2.14-dfsg-3</em>) y quiera actualizarlo... </p> <p>Ya os contaré.</p> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=39&amp;2=comment&amp;3=comment" token="LlETczWEdD9n00RfEBpV3q0sbSk9m84l5hhCSQ9IHxY"></drupal-render-placeholder> </section> </div> </article> Sat, 14 Jul 2018 20:10:45 +0000 root 39 at https://www.carloscarrascal.com Desarrollo Drupal con Sublime Editor 3 https://www.carloscarrascal.com/blog/desarrollo-drupal-con-sublime-editor-3 <article data-history-node-id="23" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Desarrollo Drupal con Sublime Editor 3 </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Sábado, Septiembre 2, 2017 - 15:20</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/drupal" hreflang="es">Drupal</a></div> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/dev" hreflang="es">Dev</a></div> <div class="field--item"><a href="/tags/php" hreflang="es">PHP</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p><a href="https://www.sublimetext.com/">Sublime Text</a> lleva siendo mi editor preferido para trabajar desde hace un montón de años. Es muy ligero, me gustan los atajos de teclado, muy configurable y tiene un sistema de <em>plugins</em> que le da mucha potencia.</p> <p>La versión 3 lleva en beta por lo menos desde 2013, y todo el tiempo que llevo usándola no he tenido problemas.</p> <p>Quería escribir un articulo con mi configuración personal que utilizo para trabajar en proyectos Drupal, y que aporta funcionalidad y facilita la vida. Como resumen:</p> <ul> <li>Revisión de código al momento: Marcado de estándares de Drupal, errores de sintaxis, etc.</li> <li>Marcado de modificaciones en Git: Cada cambio que hacemos en un fichero lo vemos resaltado, muy útil para saber de un vistazo las modificaciones que hemos hecho al archivo.</li> </ul> <p>Lo primero de todo es instalar el editor. Estamos de suerte porque tenemos paquetes binarios empaquetados para unas cuantas distribuciones Linux. Este es el enlace de descargas:</p> <p><a href="https://www.sublimetext.com/docs/3/linux_repositories.html" target="_blank">https://www.sublimetext.com/docs/3/linux_repositories.html</a></p> <p> </p> <h2>Package Control</h2> <p>La primera extensión que vamos a instalar es básica para sacarle buen partido a este editor: <a href="https://packagecontrol.io/docs/usage">Package Control</a>. Este <em>plugin</em> nos va a ayudar a instalar fácilmente otros plugins, básicamente. Para instalar paquete Package Control, vayamos a su pagina:</p> <p><a href="https://packagecontrol.io/installation" target="_blank">https://packagecontrol.io/installation</a></p> <p>Una vez instalado podremos utilizar <kbd>CTRL + SHIFT + p</kbd> para abrir una consola donde podremos ejecutar comandos.</p> <p> </p> <h2>Instalar Sublime linter</h2> <p><a href="https://github.com/SublimeLinter/SublimeLinter3">Sublime Linter</a> es un <em>plugin</em> genérico que sirve de base para otros '<em>linters</em>' mas específicos (PHP, Java, SASS, etc.) que necesitamos instalar primero. Estos <em>plugins</em> nos ayudarán a mantener nuestro código limpio y seguir los estándares del lenguaje en el que estamos programando, de forma que nos van avisando si cometemos errores de formato o sintaxis, a media que escribimos el código. Lint significa pelusa en ingles, y eso es justo lo que hacen estos <em>plugins</em>, quitar pelusa.</p> <p>Instalarlo es sencillo una vez tenemos el <em>package manager</em> instalado:</p> <ol> <li>Abrimos comandos con <kbd>CTRL+SHIFT+p</kbd></li> <li>Teclear <em>install</em> y ENTER</li> <li>buscamos el paquete SublimeLinter</li> <li>ENTER otra vez</li> </ol> <p>Y ya lo tenemos. Seguimos adelante.</p> <p> </p> <h2>Instalar PHP_CodeSniffer (phpcs)</h2> <p><a href="https://github.com/squizlabs/PHP_CodeSniffer">PHP_CodeSniffer</a> es la herramienta que nos va a ayudar a identificar cualquier violación de los estándares de PHP. Es un ejecutable que debemos instalar en nuestro sistema, por lo que necesitamos tenerlo en nuestra variable <em>PATH</em>. La ultima versión a fecha de escribir este articulo es la 3.0.2, pero para hacerlo funcionar con el modulo <em>Coder</em> de Drupal necesitamos quedarnos con la 2.7.0. Cuidado con esto que puede cambiar en el futuro, así que revisa las versiones antes de instalar.</p> <p>La forma mas sencilla de instalarlo es usando <em>pear</em>:</p> <pre> sudo pear install PHP_CodeSniffer-2.7.0</pre> <p>Con esto tendremos dos ejecutables:</p> <ul> <li><em>phpcs</em>: el "code sniffer" para inspeccionar el código y reportar errores.</li> <li><em>phpcbf</em>: el "Code Beautifier and Fixer", que se utiliza para realizar correcciones automáticas en el código.</li> </ul> <p> </p> <h2>Añadir los estándares de Drupal a phpcs. Módulo Coder</h2> <p>Ahora que ya tenemos instalado <em>phpcs</em>, necesitamos incluirle las definiciones de los estándares de código de Drupal. Para esto instalaremos el módulo <a href="https://www.drupal.org/project/coder">Coder</a> de Drupal. Vayamos a la carpeta donde lo queramos dejar instalado, que puede ser cualquier sitio, no hace falta que sea dentro de un proyecto o sitio Drupal. Eso si, antes necesitaremos tener instalado <a href="http://docs.drush.org/en/8.x/install-alternative/">Drush</a>. Por ejemplo:</p> <pre> cd /path/para/coder drush dl coder</pre> <p>Con esto deberíamos haber instalado la versión 8.x que es la última. Ahora ya podemos decir a phpcs donde están estos estándares de Drupal:</p> <pre> sudo phpcs --config-<strong>set</strong> installed_paths /path/para/coder/coder/coder_sniffer</pre> <p>Y ahora ya podemos ejecutar phpcs para revisar cualquier archivo de código Drupal, así:</p> <pre> phpcs --standard=Drupal ruta/al/archivo/a/revisar</pre> <div> </div> <h2>Volvemos a Sublime: SublimeLinter-phpcs</h2> <p>Ahora que ya tenemos <em>phpcs</em> funcionando nos volvemos a Sublime para instalar el <em>plugin</em> que vamos usar mientras picamos código, <a href="https://github.com/SublimeLinter/SublimeLinter-phpcs">SublimeLinter-phpcs</a>. Para instalarlo:</p> <ol> <li>Abrimos comandos con <kbd>CTRL+SHIFT+p</kbd></li> <li>Teclear <em>install</em> y ENTER</li> <li>buscamos el paquete <em>SublimeLinter-phpcs</em></li> <li>ENTER otra vez</li> </ol> <p>Una vez instalado el paquete, seguimos las instrucciones de configuración que nos detallan. Al final, si vamos a <em>Preferences / Package settings / Sublime linter / User</em>, debemos tener una sección en la configuración parecida a esto:</p> <pre> "linters": { "phpcs": { "@disable": false, "args": [], "excludes": [], "standard": "Drupal" } },</pre> <p>Cuando funcione, Sublime nos ira mostrando los errores que tengamos en el código de esta manera:</p> <p><img alt="SublimeLinter-phpcs" class="img-responsive shadow" src="/sites/default/files/SublimeLinter-phpcs.png" /></p> <h2>Cambios en Git: GitGutter</h2> <p>Por ultimo, otro pequeño <em>plugin</em> que nos mostrará los cambios que hayamos hecho al archivo en local, desde el último <em>commit</em> de Git. Es muy útil porque de un vistazo nos deja ver las lineas que hemos añadido, modificado o borrado del fichero. Si lo combinamos con cualquiera de los otros <em>plugins</em> de Git para Sublime, nos puede ayudar bastante para tener claro que estamos tocando.</p> <p>Instalarlo es sencillo, como los anteriores:</p> <ol> <li>Abrimos comandos con <kbd>CTRL+SHIFT+p</kbd></li> <li>Teclear <em>install</em> y ENTER</li> <li>buscamos el paquete <em>gitgutter</em></li> <li>ENTER otra vez</li> </ol> <p>Una vez este funcionando, podremos ir viendo las modificaciones que vayamos haciendo en el fichero en la parte de la izquierda, con diferentes símbolos para líneas nuevas o modificadas, como se puede ver en la siguiente imagen.</p> <p><img alt="Sublime-gitgutter" class="img-responsive shadow" src="/sites/default/files/Sublime-gitgutter.png" /></p> <h2>Preferencias generales de Sublime</h2> <p>Para terminar os dejo aquí las preferencias básicas de Sublime que utilizo con proyectos Drupal</p> <pre> { "bold_folder_labels": true, "caret_style": "wide", "default_line_ending": "unix", "draw_white_space": "all", "ensure_newline_at_eof_on_save": true, "fade_fold_buttons": false, "fallback_encoding": "UTF-8", "find_selected_text": true, "font_options": [ "subpixel_antialias" ], "highlight_line": true, "line_padding_bottom": 1, "open_files_in_new_window": false, "rulers": [ 80 ], "shift_tab_unindent": true, "soda_classic_tabs": true, "tab_size": 2, "theme": "Flatland Dark.sublime-theme", "translate_tabs_to_spaces": true, "trim_automatic_white_space": true, "trim_trailing_white_space_on_save": true, "use_tab_stops": true, "word_separators": "./\\()\"'-:,.;&lt;&gt;~!@#%^&amp;*|+=[]{}`~?", }</pre> <p> </p> <h2>Referencias</h2> <ol> <li><a href="https://packagecontrol.io/docs/usage">https://packagecontrol.io/docs/usage</a></li> <li><a href="https://www.drupal.org/node/1419988">https://www.drupal.org/node/1419988</a></li> <li><a href="https://www.drupal.org/node/2809335">https://www.drupal.org/node/2809335</a></li> <li><a href="http://benmatselby.github.io/sublime-phpcs/#configuration">http://benmatselby.github.io/sublime-phpcs/#configuration</a></li> </ol> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=23&amp;2=comment&amp;3=comment" token="IETTaxWHQ0YGdBadM3gb641wwtK9BNCdilTbGzAk9oA"></drupal-render-placeholder> </section> </div> </article> Sat, 02 Sep 2017 13:20:09 +0000 root 23 at https://www.carloscarrascal.com HTTPS con un certificado gratuito de letsencrypt.org y Certbot https://www.carloscarrascal.com/blog/https-con-un-certificado-gratuito-de-letsencryptorg-y-certbot <article data-history-node-id="16" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> HTTPS con un certificado gratuito de letsencrypt.org y Certbot </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Lunes, Febrero 27, 2017 - 22:03</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/debian" hreflang="es">Debian</a></div> <div class="field--item"><a href="/tags/servicios" hreflang="es">Servicios</a></div> <div class="field--item"><a href="/tags/ssl" hreflang="es">SSL</a></div> <div class="field--item"><a href="/tags/https" hreflang="es">HTTPS</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p><em>Let’s Encrypt</em> es una autoridad certificadora (CA) abierta, gratuita, y libre. Llevan funcionando menos de un año, desde 2016, y se puede decir que es un servicio público, dirigido a promover y facilitar la obtención y configuración de certificados de seguridad para la web. Lo que ofrecen son certificados X.509 por dominio que podemos usar para TLS.</p> <p><a href="https://letsencrypt.org/" target="_blank">https://letsencrypt.org/</a></p> <p>Hay varias organizaciones involucradas en el proyecto, siendo la principal la <a href="https://en.wikipedia.org/wiki/Internet_Security_Research_Group" target="_blank">Internet Security Research Group (ISRG)</a>, junto a otras como <a href="https://es.wikipedia.org/wiki/Fundaci%C3%B3n_Linux" target="_blank">Linux Foundation</a> o <a href="https://es.wikipedia.org/wiki/Fundaci%C3%B3n_Mozilla" target="_blank">Mozilla Foundation</a>, pero también gigantes como Akamai o Cisco Systems. Es decir, que hay gente grande detrás, y el proyecto es bastante interesante, esperemos que dure.</p> <p>Hasta ahora conseguir un certificado de seguridad para configurar HTTPS como es debido era bastante engorroso, además de que solía ser bastante caro. Últimamente los precios habían comenzado a bajar, pero ahora podemos conseguir un certificado propio por la cara, y con una instalación muy sencilla.</p> <p>La principal ventaja del servicio se basa en la automatización de todo el proceso. El objetivo es configurar un servidor HTTPS y obtener un certificado de confianza para los navegadores sin intervención humana. Y dejarme deciros que me ha funcionado de verdad, y a la primera. </p> <p>Esta automatización es la clave de todo el asunto, primero porque los certificados que nos ofrecen solamente son válidos por 90 días, lo que nos va a obligar a configurar la renovación de forma automática si no queremos estar cada tres meses renovando el certificado de forma manual.</p> <p>Para esto han ideado un protocolo llamado ACME (<a href="https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment" target="_blank">Automated Certificate Management Environment</a>), y el truco consiste en instalar un agente que se encargue de realizar automáticamente la petición y renovación del certificado, validando el solito nuestros dominios. Tenemos unos cuantos disponibles, pero el que recomiendan desde letsencrypt.org es <em>Certbot</em>:</p> <p><a href="https://certbot.eff.org" target="_blank">https://certbot.eff.org</a></p> <p><em>Certbot</em> esta empaquetado en los repos de Debian, pero deberemos usar el repositorio de <a href="https://backports.debian.org/Instructions/" target="_blank">backports</a>. Para ello basta con incluir una línea en nuestro fichero <em>/etc/apt/sources.list</em>. Si estáis usando Jessie (Debian 8) será:</p> <pre> deb http://ftp.debian.org/debian jessie-backports main</pre> <p>Después actualizamos:</p> <pre> apt-get update</pre> <p>Ahora ya podemos instalar el cliente de <em>Certbot</em>:</p> <pre> $ sudo apt-get install python-certbot-apache -t jessie-backports </pre> <p>Una vez instalado, ya podemos ejecutarlo, si estamos usando Apache, así:</p> <pre> $ certbot --apache</pre> <p>Y ya está. Lo juro. El instalador nos hará una serie de preguntas sobre los certificados que queremos instalar y listo. En mi caso tenia un Apache2 con varios VirtualHosts con diferentes nombres de dominio y alias, todos por el puerto 80. El instalador hizo solito todo esto:</p> <ul> <li>Realizo una copia de cada fichero de configuración de VirtualHost, añadiendo -le-ssl.conf al nombre, y configuró en ellos el certificado.</li> <li>En cada VirtualHost original, añadió una redirección automática a su versión de HTTPS</li> <li>Configuró un servicio en Cron <em>/etc/cron.d/certbot</em> para realizar automáticamente la renovación de los certificados.</li> <li>Reinicio el servidor Apache para cargar la nueva configuración.</li> </ul> <p>Si no os hace mucha gracia que os toque la configuración, o tenéis algo realmente chungo montado, también podemos hacer que solamente consiga el certificado, y configurarlo nosotros a mano, así:</p> <pre> $ certbot --apache certonly</pre> <p>En mi caso, añadió las siguientes líneas a mis archivos de VirtualHost originales en el 80:</p> <pre> RewriteEngine on RewriteCond %{SERVER_NAME} =xxxxx.com [OR] RewriteCond %{SERVER_NAME} =www.xxxxx.com RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent] </pre> <p>Los nuevos ficheros para SSL que creó Certbot son copias de los que yo tenía, en los que se añade la configuración del certificado:</p> <pre> SSLCertificateFile /etc/letsencrypt/live/xxxxxxx/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/xxxxxxxx/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf</pre> <p>Y este es el archivo que añade al Cron en <em>/etc/cron.d/certbot</em> para automatizar la renovación de los certificados:</p> <pre> # /etc/cron.d/certbot: crontab entries for the certbot package # # Upstream recommends attempting renewal twice a day # # Eventually, this will be an opportunity to validate certificates # haven't been revoked, etc. Renewal will only occur if expiration # is within 30 days. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system &amp;&amp; perl -e 'sleep int(rand(3600))' &amp;&amp; certbot -q renew </pre> <p>Podemos hacer una simulación del proceso de renovación de los certificados con este comando:</p> <pre> certbot renew --dry-run </pre> <p>Esto nos dará una idea de si funcionará o no cuando lo tenga que hacer el solo.</p> <p>De momento, está funcionando perfectamente. Ya veremos cuando llegue la primera renovación...</p> <p> </p> <h2>Referencias</h2> <ul> <li>Proceso de como funciona completo: <a href="https://letsencrypt.org/how-it-works/" target="_blank">https://letsencrypt.org/how-it-works/</a></li> <li>Porque 90 días: <a href="https://letsencrypt.org/2015/11/09/why-90-days.html" target="_blank">https://letsencrypt.org/2015/11/09/why-90-days.html</a></li> <li>Lista de clientes soportados: <a href="https://community.letsencrypt.org/t/list-of-client-implementations/2103" target="_blank">https://community.letsencrypt.org/t/list-of-client-implementations/2103</a></li> <li><a href="https://es.wikipedia.org/wiki/Let%27s_encrypt" target="_blank">Let's Encrypt en Wikipedia</a></li> <li><a href="https://backports.debian.org/Instructions/" target="_blank">​Debian backports</a></li> <li><a href="https://certbot.eff.org/#debianjessie-apache" target="_blank">How to install Certbot</a></li> </ul> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=16&amp;2=comment&amp;3=comment" token="EB6QcaYCufqwNDXs6N9Q8dAWj4FsozjpCPYWAbAx0pc"></drupal-render-placeholder> </section> </div> </article> Mon, 27 Feb 2017 21:03:16 +0000 root 16 at https://www.carloscarrascal.com Servidor de Git privado con Gogs https://www.carloscarrascal.com/blog/servidor-de-git-privado-con-gogs <article data-history-node-id="15" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Servidor de Git privado con Gogs </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Domingo, Febrero 19, 2017 - 01:45</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/git" hreflang="es">Git</a></div> <div class="field--item"><a href="/tags/servicios" hreflang="es">Servicios</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p><img alt="Gogs logo" class="pull-right" data-entity-type="file" data-entity-uuid="afc7ad21-f5cb-4185-a329-4b3437bf7c27" src="/sites/default/files/inline-images/gogs_logo.png" />El único problema que tengo con GitHub es que en su versión gratuita todos los repos tienen que ser públicos. Si queremos tener repositorios privados tenemos que pasar por caja, y creo que son unos 7$ al mes, que me parece cojonudo, pero en mi caso necesito minimizar al máximo el coste de mis sistemas, principalmente porque no me da dinero.</p> <p>Así que estuve investigando que alternativas tenia para instalar un servidor de Git privado. Lo primero que me vino a la cabeza fue <a href="https://about.gitlab.com/">GitLab</a>, porque lo he utilizado durante una buena temporada en el trabajo con equipos relativamente grandes y nos ha dado muy buen resultado. En mi actual empresa estamos usando <a href="https://es.atlassian.com/software/bitbucket">Bitbucket</a> de Atlasian, y prácticamente es lo mismo que teníamos con GitLab, pero al ser de pago no es una opción para mi.</p> <p>Una vez decidido a instalar GitLab, el problema está cuando te pones a mirar los <a href="https://docs.gitlab.com/ce/install/requirements.html#hardware-requirements">requisitos</a>:</p> <ul> <li>4GB de RAM es lo recomendado.</li> <li>2GB de RAM + 2GB de swap, ya te dicen que va a ir como el culo</li> <li>Se necesitan varios GB de espacio en disco solo para la instalación de GitLab</li> </ul> <p>Demasiada caña para mi pobre servidor, y mas si pienso servir desde la misma máquina un par de sitios o algún otro servicio, necesitaba algo mas ligero pero que al menos molase (ya que estamos...).</p> <p>Así que después de dar algunas vueltas e investigar un poco, acabé encontrando Gogs:</p> <p><a href="https://gogs.io/">https://gogs.io/</a></p> <p>Según ellos mismos, Gogs es:</p> <blockquote> <p>Gogs is a painless self-hosted Git service.</p> </blockquote> <p>Que viene a ser un servicio de Git que te alojas tu mismo e indoloro.</p> <p>Y la verdad es que no ha sido nada doloroso, llevo ya varios meses usándolo y ha sido una gran opción, y es que fue muy sencillo de instalar, viene con un montón de funcionalidades de serie, y tiene una interfaz muy pulida y que es calcada a GitHub.</p> <p>Entre las funcionalidades interesantes:</p> <ul> <li>Open Source</li> <li>Ligero, muy ligero. Esta ocupando menos de 500Mb en disco (con las sus fuentes y las de Go) y aun no lo he visto sobrecargar la máquina.</li> <li>Gravatar (venga va...)</li> <li>Pull request, funcionan igual que Github</li> <li>Webhooks !! (esto ya es lo mas, pero no los he probado aún)</li> <li>Notificaciones por correo</li> <li>Soporta SSH, tanto para servir la aplicación como para los repos</li> <li>Tickets para incidencias, sencillo pero útil.</li> <li>Wiki para cada proyecto</li> <li>Creación de cuentas de usuario: Con registro o manual</li> <li>Permite desactivar el registro de usuarios</li> <li>Permite configurar repositorios privados</li> <li>Webhooks, espera esto ya lo había dicho, ¿no?</li> </ul> <p> </p> <h2>Instalación</h2> <p>La ayuda oficial para la instalación la podéis encontrar aquí (todo en inglés):</p> <ul> <li>Instalación desde fuentes: <a href="https://gogs.io/docs/installation/install_from_source">https://gogs.io/docs/installation/install_from_source</a></li> <li>Ejecución: <a href="https://gogs.io/docs/installation/configuration_and_run">https://gogs.io/docs/installation/configuration_and_run</a></li> <li>Instalación avanzada: <a href="https://gogs.io/docs/advanced/configuration_for_source_builds">https://gogs.io/docs/advanced/configuration_for_source_builds</a></li> <li>Instalación desde binarios: <a href="https://gogs.io/docs/installation/install_from_binary">https://gogs.io/docs/installation/install_from_binary</a></li> </ul> <p>La instalación oficial la están haciendo con Ngnix y postgresql. Yo lo monté tirando de un viejo Apache2 y MySQL que ya tenia corriendo. Voy a hacer una traducción de la instalación que son los pasos que yo he seguido, y luego pongo mis archivos de configuración. Y ojo, que estos pasos son para instalarlo desde el fuente, que es lo que hice yo.</p> <p>Lo que queremos hacer es:</p> <ul> <li>Servir ‘Gogs’ desde un dominio midominio.com, por ejemplo como git.midominio.com</li> <li>Apache2 como servidor web</li> <li>MySQL como servidor de base de datos</li> </ul> <p>Primero creamos un usuario para que corra la aplicación:</p> <pre> $ sudo adduser --disabled-login --gecos 'Gogs' git</pre> <h3>Descarga e instalación de Go</h3> <p>Vamos a instalar Go dentro del home del usuario que acabamos de crear para no interferir con ninguna otra versión de la distribución que usemos. Usaremos</p> <pre> /home/git/local/go</pre> <p>Creamos un directorio:</p> <pre> $ sudo su - git $ cd ~ $ mkdir local </pre> <p>Bajamos la versión disponible:</p> <pre> $ wget https://storage.googleapis.com/golang/go1.7.3.linux-amd64.tar.gz $ tar -C /home/git/local -xzf go1.7.3.linux-amd64.tar.gz</pre> <p>Añadimos unas cuantas rutas al fichero bashrc de nuestro usuario git:</p> <pre> $ sudo su - git $ cd ~ $ echo 'export GOROOT=$HOME/local/go' &gt;&gt; $HOME/.bashrc $ echo 'export GOPATH=$HOME/go' &gt;&gt; $HOME/.bashrc $ echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' &gt;&gt; $HOME/.bashrc $ source $HOME/.bashrc</pre> <h3>Instalar Gogs</h3> <p>La forma rápida de instalar Gogs parece ser esta:</p> <pre> $ go get -u github.com/gogits/gogs $ cd $GOPATH/src/github.com/gogits/gogs $ go build</pre> <p>Y una vez compilado, podemos probarlo con:</p> <pre> $ cd $GOPATH/src/github.com/gogits/gogs $ ./gogs web</pre> <h2>Configuración</h2> <p>La configuración por defecto está en conf/app.ini pero no vamos a editar ese fichero. En lugar de eso Gogs nos permite crear una copia que será donde pondremos nuestras modificaciones. Primero vamos a crear unos directorios:</p> <pre> mkdir -p $GOPATH/src/github.com/gogits/gogs/custom/conf mkdir -p ~/gogs-repositories sudo mkdir -p /var/log/gogs sudo chown git:git /var/log/gogs</pre> <p>Hacemos una copia del fichero de configuración original, en donde haremos nuestros cambios:</p> <pre> cd $GOPATH/src/github.com/gogits/gogs cp conf/app.ini custom/conf/</pre> <p>En teoría en nuestro fichero de configuración 'custom' solamente deberíamos tener la configuración especifica que necesitemos. Es decir, que podemos borrar todo lo que se quede por defecto. La principal razón de esto es que cuando actualicemos la versión de Gogs, nuestra configuración no se modificará, ya que tienen un .gitignore para este fichero local. Este es el fichero que yo tengo:</p> <pre> ; Change it if you run locally RUN_USER = git ; Either "dev", "prod" or "test", default is "dev" RUN_MODE = prod [repository] ROOT = /home/git/gogs-repositories [server] PROTOCOL = http DOMAIN = git.midominio.com ROOT_URL = http://git.midominio.com/ HTTP_ADDR = 0.0.0.0 HTTP_PORT = 3000 [database] ; Either "mysql", "postgres" or "sqlite3", it's your choice DB_TYPE = mysql HOST = 127.0.0.1:3306 NAME = gogs USER = gogs PASSWD = **CONTRASEÑA** [admin] [security] INSTALL_LOCK = true ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! #@FDEWREWR&amp;*( SECRET_KEY = *KEY* ; Auto-login remember days LOGIN_REMEMBER_DAYS = 7 COOKIE_USERNAME = gogs_awesome COOKIE_REMEMBER_NAME = gogs_incredible ; Reverse proxy authentication header name of user name REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER [service] ACTIVE_CODE_LIVE_MINUTES = 180 RESET_PASSWD_CODE_LIVE_MINUTES = 180 ; User need to confirm e-mail for registration REGISTER_EMAIL_CONFIRM = false ; Does not allow register and admin create account only DISABLE_REGISTRATION = true ; User must sign in to view anything. REQUIRE_SIGNIN_VIEW = false ; Mail notification ENABLE_NOTIFY_MAIL = false [log] ROOT_PATH = /home/git/go/src/github.com/gogits/gogs/log ; Either "console", "file", "conn", "smtp" or "database", default is "console" ; Use comma to separate multiple modes, e.g. "console, file" MODE = file ; Buffer length of channel, keep it as it is if you don't know what it is. BUFFER_LEN = 10000 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" LEVEL = Info </pre> <p> </p> <h2>Configurar Apache2 con Gogs</h2> <p>Si quereis usar Nginx en lugar de Apache, la ayuda oficial tiene la info <a href="https://gogs.io/docs/advanced/configuration_for_source_builds#setting-up-nginx-sever">necesaria</a>. En Debian podemos instalar Apache2 si no lo tenemos ya:</p> <pre> sudo apt-get install apache2</pre> <p>La instalación de Gogs que acabamos de hacer corre en el puerto 3000 por defecto. Lo que queremos hacer es utilizar un servidor web como proxy para poder servir Gogs desde el puerto 80, como un subdominio de nuestro dominio, por ejemplo en este caso:</p> <pre> http://git.midominio.com</pre> <p>La mejor forma de hacer esto es crear un fichero de configuración para hacer un VirtualHost y usar mod_proxy para poder servir Gogs en el puerto 80 con Apache.</p> <pre> vi /etc/apache2/sites-available/080-gogs.conf</pre> <p>El contenido del fichero puede ser tan simple como esto:</p> <pre> &lt;VirtualHost *:80&gt; ServerName git.midominio.com ProxyPreserveHost On ProxyPass / http://localhost:3000/ ProxyPassReverse / http://localhost:3000/ ErrorLog ${APACHE_LOG_DIR}/gogs-error.log CustomLog ${APACHE_LOG_DIR}/gogs-access.log combined &lt;/VirtualHost&gt;</pre> <p>El nombre del dominio que usemos aqui será el mismo que pondremos en la configuración de Gogs. Aún tenemos que activar este VirtualHost:</p> <pre> ln -s /etc/apache2/sites-available/080-gogs.conf /etc/apache2/sites-enabled/</pre> <p>Ahora activaremos el módulo mod_proxy de Apache. Podemos probar con a2enmod:</p> <pre> $ sudo a2enmod proxy</pre> <p>Esto debería crear los dos ficheros necesarios dentro de <em>/etc/apache2/mods-enabled/ : proxy.conf y proxy.load</em></p> <p>Reiniciar Apache y a correr. Con suerte no tendreis ningún error.</p> <pre> $ sudo service apache2 restart</pre> <p> </p> <h2>Configurar MySQL</h2> <p>No voy a entrar en detalles sobre la configuración inicial de MySQL, porque eso daría para un libro entero. En principio bastará con crear una base de datos nueva y asignar todos los permisos a un usuario para Gogs:</p> <pre> CREATE DATABASE gogs CHARACTER SET utf8 COLLATE utf8_general_ci; GRANT ALL PRIVILEGES ON gogs.* To 'gogs'@'localhost' IDENTIFIED BY 'password';</pre> <p>Lo suyo sería ahora verificar la conexión a la nueva base de datos para estar seguros de que funciona correctamente, por ejemplo, desde la linea de comandos:</p> <pre> mysql --user=gogs --password=password --host=localhost gogs</pre> <p> </p> <h2>Ejecutar el instalador</h2> <p>Llegado este punto deberíamos tener todo lo necesario para arrancar el dichoso Gogs. Lo arrancamos manualmente con:</p> <pre> $ cd $GOPATH/src/github.com/gogits/gogs $ ./gogs web</pre> <p>Si ahora usamos un navegador para acceder a la dirección que hayamos configurado en nuestro Apache, deberiamos acceder a la primera pantalla del instalador, que nos guiará por la configuración básica. En nuestro ejemplo seria:</p> <pre> http://git.midominio.com</pre> <p> </p> <h2>Añadir Gogs a init.d</h2> <p>Llegados a este punto todo deberia estar funcionando, sin embargo necesitamos arrancar Gogs a mano. Lo que necesitamos es poder levantar y parar Gogs como un servicio mas de nuestra máquina, y además, que este arranque automaticamente al levantar o reiniciar el servidor.</p> <p>Para esto los chavales de Gogs nos han preparado una plantilla que nos facilitará mucho las cosas (para Debian / Ubuntu). Esta aqui:</p> <pre> $GOPATH/src/github.com/gogits/gogs/scripts/init/debian/gogs</pre> <p>La copiamos al directorio de init.d:</p> <pre> $ sudo cp $GOPATH/src/github.com/gogits/gogs/scripts/init/debian/gogs /etc/init.d/gogs</pre> <p>Y ahora modificamos un par de cosas. Editaremos las dos primeras lineas:</p> <pre> # Required-Start: $syslog $network # Required-Stop: $syslog </pre> <p>De esta manera</p> <pre> # Required-Start: $syslog $network $local_fs apache2 mysql # Required-Stop: $syslog $local_fs </pre> <p>Y nos aseguramos de que la variable WORKINGDIR apunte al directorio correcto:</p> <pre> WORKINGDIR=/home/git/go/src/github.com/gogits/gogs</pre> <p>El script necesita permisos de ejecución, y lo añadimos a la configuración de inicio:</p> <pre> $ sudo chmod ug+x /etc/init.d/gogs $ sudo update-rc.d gogs defaults 30 70 </pre> <p>Ahora podemos probar nuestra configuración y levantar el servicio gogs:</p> <pre> $ sudo service gogs start</pre> <p>Y conectar con un navegador a la URL que hemos configurado</p> <pre> http://git.midominio.com</pre> <p>Listo, espero que disfrutéis tanto como yo montando este pollo. Ahora ya nadie podrá ver los WTF que tenéis en vuestro código.</p> <p> </p> <p> </p> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=15&amp;2=comment&amp;3=comment" token="EQr7U62Ohq-jqYwGuQE5z60d5XQ-npXesPuXroqMZ3M"></drupal-render-placeholder> </section> </div> </article> Sun, 19 Feb 2017 00:45:21 +0000 root 15 at https://www.carloscarrascal.com Problemas con Baloo en KDE4 en Debian Sid https://www.carloscarrascal.com/blog/problemas-con-baloo-en-kde4-en-debian-sid <article data-history-node-id="12" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Problemas con Baloo en KDE4 en Debian Sid </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Lunes, Octubre 19, 2015 - 12:20</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/debian" hreflang="es">Debian</a></div> <div class="field--item"><a href="/tags/sid" hreflang="es">Sid</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p>Con las últimas actualizaciones el indexador de Baloo se esta volviendo loco y se lleva la CPU como un salvaje.</p> <p>Como no se puede desactivar con un servicio o por medio del /etc/init.d, y no quería que siguiese activo, he estado buscando como desactivarlo. Al final lo que he hecho es editar el fichero de configuración</p> <pre> $HOME/.kde/share/config/baloofilerc</pre> <p>y añadir esto:</p> <pre> Indexing-Enabled=false</pre> <p>Después maté el proceso baloo_file_extractor con un kill y se acabó el problema.</p> <p>En <a href="http://ubuntuforums.org/showthread.php?t=2217434">este hilo</a> de los foros de Ubuntu teneis mas info.</p> <p> </p> <p> </p> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=12&amp;2=comment&amp;3=comment" token="gsI_b4s7jeSkQ5EGNx2lBXiItBywcZaYbU-FLbZT6U0"></drupal-render-placeholder> </section> </div> </article> Mon, 19 Oct 2015 10:20:25 +0000 root 12 at https://www.carloscarrascal.com Instalar compilador de less en Debian https://www.carloscarrascal.com/blog/instalar-compilador-de-less-en-debian <article data-history-node-id="14" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Instalar compilador de less en Debian </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Sábado, Octubre 3, 2015 - 01:24</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/debian" hreflang="es">Debian</a></div> <div class="field--item"><a href="/tags/less" hreflang="es">less</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p>Primero vamos a probar la versión rápida y sencilla, que es con el paquete de Debian, que instalamos como <em>root</em>:</p> <pre> # apt-get install node-less</pre> <p>Esto nos instalará el paquete principal de <em>node.js</em> y el compilador de <em>less</em>. Ahora ya podemos probar el compilador, con salida por <em>stdout</em>:</p> <pre> $ lessc styles.less</pre> <p>O con salida a un fichero</p> <pre> $ lessc styles.less &gt; styles.css</pre> <p>Al ser un paquete de Debian, es posible que esta versión no este muy actualizada. En mi caso en el momento de instalarlo la versión que ha traido es esta (en Debian Sid):</p> <pre> $ lessc --version lessc 1.6.3 (LESS Compiler) [JavaScript] </pre> <p>Si queremos tirar de una versión mas actualizada, es mejor instalarlo de otra manera, que es con el gestor de paquetes de <em>node.js</em>: <a href="https://www.npmjs.com/">npm</a>. Para ello, lo instalamos tirando del paquete de Debian:</p> <pre> # apt-get install npm</pre> <p>Y después instalamos <em>less</em> usando <em>npm</em>, con la opción -g para que lo instale global todo el sistema (hacer esto como root):</p> <pre> # npm install -g less</pre> <p>Y comprobamos la versión, mucho mas nueva:</p> <pre> lessc --version lessc 2.5.3 (Less Compiler) [JavaScript]</pre> <p>En mi caso, al instalar con <em>npm</em>, se hace un lío con el ejecutable de node.js, que en unos sitios es <em>node</em> y en otros <em>nodejs</em>, y al ejecutar da errores como este:</p> <pre> lessc /usr/bin/env: node: No existe el fichero o el directorio </pre> <p>Esto tiene fácil solución, creando un enlace dinámico para que lo encuentre (también hay que hacer esto como root):</p> <pre> # ln -s /usr/bin/nodejs /usr/bin/node</pre> <p>Eso es todo. Supongo que la mayoría funcionara también en Ubuntu, pero eso ya os lo dejo a vosotros...</p> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=14&amp;2=comment&amp;3=comment" token="fmIfbiR8nl0e3Twra6AbI8B26q-U9xssL7b2YNbxsOs"></drupal-render-placeholder> </section> </div> </article> Fri, 02 Oct 2015 23:24:29 +0000 root 14 at https://www.carloscarrascal.com Encontrar procesos que causan bloqueos de IO (iowait) https://www.carloscarrascal.com/blog/encontrar-procesos-que-causan-bloqueos-de-io-iowait <article data-history-node-id="9" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Encontrar procesos que causan bloqueos de IO (iowait) </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Viernes, Junio 12, 2015 - 00:21</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/debian" hreflang="es">Debian</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p><em>IOWait</em> es la medida del tiempo que los procesos de la CPU pasan sin hacer nada, en espera de poder hacer una operación de IO, es decir, leer o escribir en el disco.</p> <p>Generalmente es un indicador claro de un cuello de botella en el sistema, y se produce cuando alguno de los discos (o todos) no dan a basto con operaciones de lectura y/o escritura.</p> <p>Los síntomas suelen ser bastante claros, en forma de bajada general de rendimiento, largas esperas, etc.</p> <p>La forma más sencilla y estándar de comprobar la carga de iowait que tenemos es usar el comando <em>top</em>, que tenemos disponible en cualquier sistema GNU / Linux, y en muchos casos no es necesario ni siquiera tener permisos de root. En la primera parte de la salida del top es donde tenemos esta información en la línea de %Cpu(s), marcada como <em>wa</em>.</p> <pre> top - 20:26:25 up 5 days, 22:50, 3 users, load average: 0,02, 0,31, 0,54 Tasks: 220 total, 1 running, 219 sleeping, 0 stopped, 0 zombie %Cpu(s): 3,3 us, 1,8 sy, 0,0 ni, 94,3 id, 0,7 wa, 0,0 hi, 0,0 si, 0,0 st KiB Mem : 7614832 total, 144824 free, 2784012 used, 4685996 buff/cache KiB Swap: 7815164 total, 7718864 free, 96300 used. 4251800 avail Mem </pre> <p>En este caso, según la salida de top, tenemos 3,3% de procesos de usuario (us), 1,8% un de sistema (sy), 0,0% de procesos de baja prioridad (ni), un 94,3% de CPU sin hacer nada, o en estado idle (id), y solamente un 0,7% de iowait (wa), lo cual está bastante bien. El resto está a cero, y si hacemos la suma sale un 100,1 %. Cosas del redondeo...</p> <p>Para refrescar, según la información de man del comando top...</p> <pre> us: user cpu time (or) % CPU time spent in user space sy: system cpu time (or) % CPU time spent in kernel space ni: user nice cpu time (or) % CPU time spent on low priority processes id: idle cpu time (or) % CPU time spent idle wa: io wait cpu time (or) % CPU time spent in wait (on disk) hi: hardware irq (or) % CPU time spent servicing/handling hardware interrupts si: software irq (or) % CPU time spent servicing/handling software interrupts st: steal time - - % CPU time in involuntary wait by virtual cpu while hypervisor is servicing another processor (or) % CPU time stolen from a virtual machine </pre> <p>Ahora veamos un ejemplo de proceso generando esperas de <em>iowait</em>. Lo que voy a hacer es ejecutar un comando sencillo pero que va a generar muchas operaciones de lectura, en este caso, un simple du para comprobar el espacio usado, pero sobre el raiz del sistema de ficheros:</p> <pre> du -h /</pre> <p>Al ejecutar el comando, los resultados del <em>top</em> ya empiezan a mostrar una subida del iowait.</p> <pre> Tasks: 226 total, 3 running, 223 sleeping, 0 stopped, 0 zombie %Cpu(s): 11,5 us, 6,5 sy, 2,0 ni, 60,8 id, 19,0 wa, 0,0 hi, 0,1 si, 0,0 st KiB Mem : 7614832 total, 52068 free, 3388748 used, 4174016 buff/cache KiB Swap: 7815164 total, 7711876 free, 103288 used. 3580684 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2356 charles 20 0 882788 147036 83488 S 17,6 1,9 0:30.12 chrome 2513 charles 20 0 7076 3156 2384 D 14,6 0,0 0:02.09 du 12156 charles 20 0 564288 62128 43656 S 13,6 0,8 0:36.61 konsole 2442 charles 20 0 623544 182416 134288 S 7,0 2,4 26:52.05 chrome </pre> <p>Aquí podemos ver que el %wa ha subido al 19,0%, con lo que vamos a empezar a notar problemas de rendimiento. En este caso, y solamente usando el comando top, podemos identificar rápidamente el proceso, fijándonos en la columna de estado (S) del top, vemos que hay un proceso <em>du</em> que tiene su estado a D. El estado D significa 'uninterruptible sleep', lo que suele ser indicativo de que el proceso está esperando por una operación de IO.</p> <p>También para refrescar, esta es la lista de estados que muestra el man del comando <em>top</em>.</p> <pre> D = uninterruptible sleep R = running S = sleeping T = stopped by job control signal t = stopped by debugger during trace Z = zombie </pre> <p>Normalmente, los procesos en <em>top</em> estarán en estado S (durmiendo a gusto) o R (corriendo). Si empezamos a ver procesos en D, es señal de que estamos teniendo lo esperas largas de IO.</p> <p>Para sacar algo más de información de que están haciendo nuestros procesos conflictivos, otro comando muy útil y más específico el <em>top</em> es <em>iotop</em>. Ojo, porque este no viene "de serie" en la mayoría de distribuciones, aunque es muy recomendable tenerlo a mano. En Debian, lo tenemos sencillo:</p> <pre> apt-get install iotop</pre> <p>Con <em>iotop</em> tenemos un listado del uso de operaciones de IO por procesos. La primera información que nos muestra son los totales de lectura y escritura del sistema, y después las de cada proceso ordenados por actividad. Y aquí sí que podremos ver de forma muy clara cuáles son los procesos que más recursos están utilizando.</p> <pre> Total DISK READ : 1265.11 K/s | Total DISK WRITE : 0.00 B/s Actual DISK READ: 875.85 K/s | Actual DISK WRITE: 0.00 B/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO&gt; COMMAND 14344 be/4 charles 1265.11 K/s 0.00 B/s 0.00 % 64.06 % du -h / 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init 2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd] 3 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/0] 5 be/0 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/0:0H] </pre> <p>Ahora si podemos ver sin duda que el proceso <em>du</em> es el que está leyendo del disco como si no hubiese mañana, y bueno, en este caso la solución es sencilla: podemos matarlo con un <em>kill</em>, con el PID que nos da el <em>iotop</em>.</p> <pre> kill 14344</pre> <p>Si queremos seguir investigando un poco más, podemos usar el comando <em>lsof</em>, que nos va a mostrar un listado de los archivos que está utilizando un proceso, con su PID:</p> <pre> lsof -p 14344</pre> <p>La salida mostrará algo parecido a lo que vemos a continuación, y en muchos casos también nos puede dar pistas de lo que está sucediendo.</p> <pre> COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME du 14883 charles rtd DIR 252,0 4096 2 / du 14883 charles txt REG 252,0 113576 5796815 /usr/bin/du du 14883 charles mem REG 252,0 341146 10477596 /usr/share/locale/es/LC_MESSAGES/coreutils.mo du 14883 charles mem REG 252,0 1729984 13221996 /lib/x86_64-linux-gnu/libc-2.19.so du 14883 charles mem REG 252,0 140928 13221991 /lib/x86_64-linux-gnu/ld-2.19.so du 14883 charles mem REG 252,0 1607632 4309902 /usr/lib/locale/locale-archive du 14883 charles mem REG 252,0 151111 16318536 /usr/share/locale/es/LC_MESSAGES/libc.mo du 14883 charles mem REG 252,0 26258 4322370 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache du 14883 charles 0u CHR 136,1 0t0 4 /dev/pts/1 du 14883 charles 1u CHR 136,1 0t0 4 /dev/pts/1 du 14883 charles 2u CHR 136,1 0t0 4 /dev/pts/1 </pre> <p>Otro comando útil para estos casos es <em>iostat</em>, que nos muestra estadísticas de operaciones de IO sobre los discos. En este caso, no tenemos información de los procesos que las causan, solamente las operaciones globales que se están realizando, y principalmente nos va a permitir descubrir, o confirmar, en cuál de nuestros discos es en el que se están produciendo los bloqueos.</p> <p>Al igual que con <em>iotop</em>, normalmente tendremos que instalarlo a parte. En Debian:</p> <pre> apt-get install iostat</pre> <p>La primera muestra de iostat nos muestra el resumen total desde que levantó la máquina, y en las siguientes iteraciones se muestra la estadística desde el informe anterior, y es donde podremos ver que está pasando.</p> <pre> iostat 2</pre> <p>La salida de <em>iostat</em>, con iteraciones cada 2 segundos:</p> <pre> Linux 4.2.0-1-amd64 (totoro2) 20/10/15 _x86_64_ (4 CPU) avg-cpu: %user %nice %system %iowait %steal %idle 2,38 0,32 1,15 2,69 0,00 93,45 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 31,91 84,58 725,86 7867640 67517095 dm-0 37,82 83,47 723,61 7764404 67308108 dm-1 0,64 0,59 2,00 54648 185684 avg-cpu: %user %nice %system %iowait %steal %idle 4,79 0,00 2,52 24,34 0,00 68,35 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 573,50 2304,00 18,00 4608 36 dm-0 580,50 2304,00 18,00 4608 36 dm-1 0,00 0,00 0,00 0 0 avg-cpu: %user %nice %system %iowait %steal %idle 5,51 0,00 2,38 23,53 0,00 68,59 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 197,00 780,00 10,00 1560 20 dm-0 197,00 780,00 10,00 1560 20 dm-1 0,00 0,00 0,00 0 0 </pre> <p>En este caso, vemos que tenemos un iowait de alrededor de un 24%, que se está produciendo en el disco <em>sda</em>. Este comando es muy útil cuando tenemos varios, por ejemplo, y podemos combinar con <em>lsof</em> para indagar más sobre los ficheros que están causando el problema.</p> <p>A partir de aquí, las soluciones dependen del tipo de problema que tengamos entre mano, y eso ya daría no para otro artículo, sino para un libro entero, pero siempre podremos recurrir a nuestro querido <em>kill</em>, al menos para quedarnos agusto.</p> <p>Para ampliar un poco de información, y como fuentes que he utilizado para consulta, recomiendo varias lecturas interesantes, aunque todas en inglés.</p> <p><a href="http://serverfault.com/questions/12679/can-anyone-explain-precisely-what-iowait-is">http://serverfault.com/questions/12679/can-anyone-explain-precisely-wha…</a></p> <p><a href="http://stackoverflow.com/questions/666783/how-to-find-out-which-process-is-consuming-wait-cpu-i-e-i-o-blocked">http://stackoverflow.com/questions/666783/how-to-find-out-which-process…</a></p> <p><a href="http://bencane.com/2012/08/06/troubleshooting-high-io-wait-in-linux/">http://bencane.com/2012/08/06/troubleshooting-high-io-wait-in-linux/</a></p> <p> </p> </div> </div> <div class="group-footer"> <section> <h2>Comments</h2> <article data-comment-user-id="0" id="comment-1" about="/en/comment/1" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1505613789"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Maria Fargas (no verificado)</span> el Dom, 17/09/2017 - 04:00</span> <span property="schema:dateCreated" content="2017-09-17T02:00:12+00:00" class="hidden"></span> </p> <a href="/en/comment/1#comment-1" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/1#comment-1" class="permalink" rel="bookmark" hreflang="en">IO Wait</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>Muchas gracias por este blog.. Me ayudó mucho..</p> <p>Saludos.</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=1&amp;1=default&amp;2=en&amp;3=" token="f2l6E3exSxFDxa_4V_oxZaC4lhbUjGxcEMIVDS7iiXI"></drupal-render-placeholder> </div> </article> <article data-comment-user-id="0" id="comment-77" about="/en/comment/77" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1565734646"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Angel (no verificado)</span> el Jue, 28/02/2019 - 23:36</span> <span property="schema:dateCreated" content="2019-02-28T22:36:44+00:00" class="hidden"></span> </p> <a href="/en/comment/77#comment-77" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/77#comment-77" class="permalink" rel="bookmark" hreflang="en">buena info, se agradece</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>buena info, se agradece</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=77&amp;1=default&amp;2=en&amp;3=" token="fBZeHvMTZ-hMcEU-2GyaXcKJQN-wkiJ1-4A0Y2WoWH0"></drupal-render-placeholder> </div> </article> <article data-comment-user-id="0" id="comment-88" about="/en/comment/88" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1565734598"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Francisco Sánchez (no verificado)</span> el Vie, 12/04/2019 - 13:51</span> <span property="schema:dateCreated" content="2019-04-12T11:51:56+00:00" class="hidden"></span> </p> <a href="/en/comment/88#comment-88" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/88#comment-88" class="permalink" rel="bookmark" hreflang="en">IO Wait</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>Muchas gracias por esta entrada, Carlos. Me resultó muy útil</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=88&amp;1=default&amp;2=en&amp;3=" token="yNROpDxHetycA7X96bZ0aaei_TH6OlLk12xsiZxQxwI"></drupal-render-placeholder> </div> </article> <article data-comment-user-id="0" id="comment-244" about="/en/comment/244" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1619643910"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Gracias (no verificado)</span> el Dom, 17/05/2020 - 18:17</span> <span property="schema:dateCreated" content="2020-05-17T16:17:52+00:00" class="hidden"></span> </p> <a href="/en/comment/244#comment-244" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/244#comment-244" class="permalink" rel="bookmark" hreflang="en">Util</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>Me ha resultado muy util, me estaba volviendo loco.</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=244&amp;1=default&amp;2=en&amp;3=" token="eD-S_AZaNj6gnYHVX1mZoAboODL9hfCuk8Y381ywGG0"></drupal-render-placeholder> </div> </article> <article data-comment-user-id="0" id="comment-245" about="/en/comment/245" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1619643702"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Gracias (no verificado)</span> el Dom, 17/05/2020 - 18:18</span> <span property="schema:dateCreated" content="2020-05-17T16:18:17+00:00" class="hidden"></span> </p> <a href="/en/comment/245#comment-245" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/245#comment-245" class="permalink" rel="bookmark" hreflang="en">Me ha resultado muy util</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>Gracias me estaba volviendo loco</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=245&amp;1=default&amp;2=en&amp;3=" token="kFYKxrJs877MYmVl2h2d9EMQ4Z7OwWWn6_qIe91Rzpc"></drupal-render-placeholder> </div> </article> <article data-comment-user-id="0" id="comment-401" about="/en/comment/401" typeof="schema:Comment" class="js-comment"> <mark class="hidden" data-comment-timestamp="1619644036"></mark> <footer> <article typeof="schema:Person" about="/user/0"> </article> <p><span rel="schema:author">Subido por <span lang="" typeof="schema:Person" property="schema:name" datatype="">Elizabeth (no verificado)</span> el Mar, 04/08/2020 - 14:11</span> <span property="schema:dateCreated" content="2020-08-04T12:11:52+00:00" class="hidden"></span> </p> <a href="/en/comment/401#comment-401" hreflang="en">Enlace permanente</a> </footer> <div> <h3 property="schema:name" datatype=""><a href="/en/comment/401#comment-401" class="permalink" rel="bookmark" hreflang="en">Artículo IO</a></h3> <div property="schema:text" class="field field--name-comment-body field--type-text-long field--label-hidden field--item"><p>Hola, quiero agradecerte por este blog y este artículo, lo explicas de una manera sencilla y muy fácil de entender.</p> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=401&amp;1=default&amp;2=en&amp;3=" token="TyKpyKFb6UbOHCwcl1jBaUwheVDtJ9Ld7fr39ZcVknI"></drupal-render-placeholder> </div> </article> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=9&amp;2=comment&amp;3=comment" token="1g0_Z49MsJ1d2YR9jPRW7ku1mahA70BrmRzz7aT_CCI"></drupal-render-placeholder> </section> </div> </article> Thu, 11 Jun 2015 22:21:19 +0000 root 9 at https://www.carloscarrascal.com Normalización de volumen de mp3 https://www.carloscarrascal.com/blog/normalizacion-de-volumen-de-mp3 <article data-history-node-id="17" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Normalización de volumen de mp3 </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Lunes, Abril 28, 2014 - 22:28</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/audio" hreflang="es">Audio</a></div> <div class="field--item"><a href="/tags/mp3" hreflang="es">mp3</a></div> <div class="field--item"><a href="/en/tags/mp3gain" hreflang="en">mp3gain</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p>Con los años mi colección de mp3 no para de crecer, hace años que no utilizo otro soporte para la música, pero como las fuentes son muy variadas, siempre hay cambios de volumen entre las distintas canciones cuando uno esta reproduciendo distintos álbumes o artistas. Esto es especialmente molesto en el coche, o a las tres de la mañana, susto incluido.</p> <p>Hace tiempo descubrí una herramienta para normalizar el volumen de audio en los mp3, que me viene funcionando de maravilla, llamada <em>mp3gain</em>.</p> <p>En Debian, lo podemos instalar sin mucho problema:</p> <pre> apt-get install mp3gain </pre> <p>Lo que hago es ejecutarlo con un comando en el directorio donde guardo la música:</p> <pre> find . -type f -iname "*.mp3" -exec mp3gain -k -r "{}" \; </pre> <p>Lo que hace este comando es ejecutar <em>mp3gain</em> sobre todos los archivos mp3 del disco, procurando que una subida de volumen no haga distorsionar el audio (parámetro -k), y equiparando el volumen de todas las pistas al mismo nivel (parámetro -r).</p> <p>En teoria estos ajustes sobre los archivos son <em>"lossless"</em>, es decir, sin pérdida de calidad, ya que no se recodifican los datos, sino que se aplican directamente los cambios sobre el fichero. También tiene un modo de funcionamiento que guarda los ajustes solamente en una etiqueta del fichero, pero de esta forma nuestro reproductor tendrá que saber procesar dicha etiqueta. Yo no he tenido ningún problema haciendo los ajustes directamente a los ficheros.</p> <p>Para más información, la página del proyecto es:</p> <p><a href="http://mp3gain.sourceforge.net/" target="_blank">http://mp3gain.sourceforge.net/</a></p> <p> </p> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=17&amp;2=comment&amp;3=comment" token="B_jr1cz7gicq8lxY4PqWeJI7K26EGwp7nNbZxPjUVjE"></drupal-render-placeholder> </section> </div> </article> Mon, 28 Apr 2014 20:28:48 +0000 root 17 at https://www.carloscarrascal.com Script de backup para Drupal https://www.carloscarrascal.com/blog/script-de-backup-para-drupal <article data-history-node-id="5" class="node node--type-blog-post node--view-mode-rss group-one-column ds-2col-stacked-fluid clearfix"> <div class="group-header"> <div class="field field--name-node-title field--type-ds field--label-hidden field--item"><h1> Script de backup para Drupal </h1> </div> <div class="field field--name-node-post-date field--type-ds field--label-hidden field--item">Lunes, Abril 28, 2014 - 21:12</div> </div> <div class="group-left"> <div class="field field--name-field-tags field--type-entity-reference field--label-hidden field--items"> <div class="field--item"><a href="/tags/drupal" hreflang="es">Drupal</a></div> <div class="field--item"><a href="/tags/linux" hreflang="es">Linux</a></div> <div class="field--item"><a href="/tags/backup" hreflang="es">Backup</a></div> </div> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><p>Cuando hablamos de Drupal, el espectro de productos desarrollados con el es amplísimo. Me refiero a que podemos encontrar desde pequeños portales montados con lo justo y desplegados en un pequeño servidor, hasta completos sites empresariales con varios nodos frontales, balaceadores de carga, cluster de bases de datos, etc.</p> <p>Normalmente en proyectos grandes se dispone de copias de seguridad de ficheros y bases de datos, por cuenta de los chicos de sistemas, pero este tipo de backups suelen ser complicados de restaurar, por afectar a mas componentes del sistema opertivo ademas de nuestro querido Drupal que se nos acaba de romper. Además, muchas veces ni siquiera pueden ser restaurados por el equipo de desarrollo, con lo que en la práctica no suele ser recomendable fiarnos solo de este tipo de respaldos.</p> <p>Si queremos estar tranquilos, lo mejor es verlo de esta manera: hoy en día, el espacio en disco es barato.</p> <p>En la mayoría de los casos, lo normal será que tengamos espacio disponible en disco que podemos usar para realizar nuestros propios backups, programados con una sencilla tarea en el crontab de la máquina, digamos suficiente para guardar una copia diaria durante al menos una semana.</p> <p>Para ello, suelo utilizar alguna variación de este script, que saca copia de la base de datos y del directorio fisico que le indiquemos, con lo que tendremos un backup completo del sitio Drupal en dos ficheros.</p> <p>Para utilizar este script necesitaremos:</p> <ul> <li>mysqldump, como herramienta para realizar la copia de la BBDD</li> <li>tar, como herramienta para generar un archivo comprimido de los ficheros.</li> </ul> <p><strong>OJO:</strong> Cuidado <u>donde dejamos este script y los permisos del fichero</u>, ya que tendremos en el los datos de acceso al MySQL de Drupal. No podemos tenerlo en un directorio público y su juego de permisos deberia ser algo como 700, dependiendo de como lo vayamos a ejecutar.</p> <p> </p> <pre> #!/bin/bash # DATOS DRUPAL_FILES=/var/www/nuestro-drupal BACKUP_DIR=/la/carpeta/raiz/de/backup FILENAME=drupal_auto_backup_ USER=usuarioBBDD PASSWORD=passwordBBDD DATABASE=nombreBBDD HOST=hostBBDD # Numero de dias a conservar los ficheros DIAS=7 # COMIENZO DATE=`date +%Y"-"%m"-"%d"--"%H"-"%M` PATH_MYSQL=$BACKUP_DIR/ddbb/ PATH_FILES=$BACKUP_DIR/files/ if [ ! -d "$PATH_MYSQL" ]; then echo "Creando directorio $PATH_MYSQL" mkdir -p $PATH_MYSQL fi if [ ! -d "$PATH_FILES" ]; then echo "Creando directorio $PATH_FILES" mkdir -p $PATH_FILES fi FILE_MYSQL=$PATH_MYSQL$FILENAME$DATE".sql" FILE_TAR=$PATH_FILES$FILENAME$DATE".tar.gz" echo "Generando backup de MySQL $FILE_MYSQL" mysqldump --user=$USER --password=$PASSWORD --host=$HOST $DATABASE  &gt; $FILE_MYSQL echo "Generando backup de ficheros $FILE_TAR" cd $DRUPAL_FILES tar cvvzf $FILE_TAR * echo "Eliminando backups antiguos" find $PATH_MYSQL -type f -name "$FILENAME*" -mtime +$DIAS -exec rm -v {} \; find $PATH_FILES -type f -name "$FILENAME*" -mtime +$DIAS -exec rm -v {} \; </pre> </div> </div> <div class="group-footer"> <section> <h2>Añadir nuevo comentario</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=5&amp;2=comment&amp;3=comment" token="FDpRQwYdbnmWRnYAH9qRd8tLV8cpeL87AjLAWjYuDfg"></drupal-render-placeholder> </section> </div> </article> Mon, 28 Apr 2014 19:12:10 +0000 root 5 at https://www.carloscarrascal.com