ftp mirroring con lftp

He necesitado hacer un mirror de unos directorios que sólo estaban disponibles por ftp y necesito lanzar sincronizaciones periódicas de forma sencilla y cómoda, para ello he usado lftp una vieja herramienta que tenía ya enterrada.

Instalar lftp

apt-get install lftp

Lo más útil de lftp es la capacidad de copiar directorios de forma recursiva ya que por defecto el cliente ftp de toda la vida de las distrubicones de linux no lo soporta.

Como puedo hacer un mirroring:

lftp -u usuario,password ftp.midominio.tld
mirror /ruta/ftp/origen /ruta/local/b

 

ls: Fatal error: Certificate verification: Not trusted

Este error aparece cuando nuestro lftp no es capaz de verificar que el certificado remoto sea válido por lo que no nos permite continuar realizando operaciones en la máquina remota. Esto está bien, si el certificado es correcto, pero habitualmente nos encontraremos con certificados incorrectos o caducados, por lo que podremos desactivarlo, ya que no nos ofrece ningún nivel de seguridad, si el certificado no está correctamente instalado.

Para desactivarlo, yo he usado esta opción con éxito ( aunque hay varias variantes buscando en google ):

set ftp:ssl-allow no;

A lo que tengo que añadir que después de ejecutar este comando con el debug activo:

set debug 10

me ha sido imposible retornar el listado de directorios, y parece ser un bug. Este caso se observa al lanzar el comando `ls` y ver infinitamente el texto: Delaying before reconnect.

Desactivado el debug, funciona correctamente

set debug 0

Mirroring sites using ftp

Aquí os dejo un pequeño script para hacer migración de sitios usando ftp de una forma bastante rápida:

FTP_USER="tu usuario"
FTP_PASSWORD="tu password"
FTP_HOST=ftp.dominio.ltd
SOURCE=/ruta/remota/origen
DEST=/ruta/remota/destino
lftp -u"${FTP_USER},${FTP_PASSWORD}" -e "set ftp:ssl-allow no; mirror ${SOURCE} ${DEST} --only-newer --verbose --use-pget-n=10; quit" ${FTP_HOST}

A tener en cuenta:

  • -u»usuario,password» Es necesario usar las comillas ya que de esa forma escapamos los caracteres especiales que pueda tener el password
  • -e«ejecuta comandos una vez que abre la conexión»
  • set ftp:ssl-allow no No valida el certificado ssl del servidor ftp
  • –only-newer Sólo ficheros nuevos
  • –use-pget n=10 Usa 10 conexiones concurrentes

vagrant ansible sys.stdout.enconding is None

Estoy desplegando una máquina con vagrant y ansible en la que use vars_promt, mi intención es hacer una serie de preguntas previas al despliegue de una máquina y llevaba un buen rato pegándome con un error, concretamente este :

Traceback (most recent call last):
  File "/usr/bin/ansible-playbook", line 309, in <module>
    sys.exit(main(sys.argv[1:]))
  File "/usr/bin/ansible-playbook", line 249, in main
    pb.run()
  File "/usr/lib/python2.7/dist-packages/ansible/playbook/__init__.py", line 305, in run
    play = Play(self, play_ds, play_basedir, vault_password=self.vault_password)
  File "/usr/lib/python2.7/dist-packages/ansible/playbook/play.py", line 65, in __init__
    self.vars             = self._get_vars()
  File "/usr/lib/python2.7/dist-packages/ansible/playbook/play.py", line 672, in _get_vars
    vname, private, prompt, encrypt, confirm, salt_size, salt, default
  File "/usr/lib/python2.7/dist-packages/ansible/callbacks.py", line 662, in on_vars_prompt
    result = prompt(msg, private)
  File "/usr/lib/python2.7/dist-packages/ansible/callbacks.py", line 648, in prompt
    msg = prompt.encode(sys.stdout.encoding)
TypeError: encode() argument 1 must be string, not None
Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.

Leer el traceback de python al principio es un poco ruidoso, pero hay que leer detenidamente la traza y veremos claramente el problema. Yo al principio no lo he hecho y eso me ha llevado a dedicarle más tiempo 😀

Existe un problema documentado en ansible que genera este error cuando no es capaz de generar la codificación de salida, no se si es exactamente un bug de python2.x o es de ansible, por que en algunos casos recomiendan directamente migrar a python3 aunque ansible está desarrollado con python2.7.

Si queréis entreneros veréis que efectivamente sys.stdout.enconding devuelve None y de ahí la execepción que genera ansible.

Ahora bien,¿ como lo solucionamos ? forzando un tipo de codificacion con la variable de entorno PYTHONIOENCODING

export PYTHONIOENCODING='utf-8'

De esta manera ya podemos lanzar el provisionamiento de la máquina

vagrant provision

Esto está bien, pero no es práctico, ya que lo que queremos es olvidarnos de tener que hacer cosas manualmente, por eso automatizamos. Pues bien, hay una forma de agregar esto, y dejar nuestro Vagrantfile más o menos así:

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  config.vm.box = "debian/jessie64"

  #Force sys.stdout.encoding to utf8
  ENV['PYTHONIOENCODING'] = "utf-8"

  config.vm.provision "ansible" do |ansible|
      ansible.verbose = "v"
      ansible.playbook = "ansible/playbook.yml"
  end

end

Evidentemente esto es un fichero muy sencillo, lo importante es declarar la variable de entorno

 

  ENV['PYTHONIOENCODING'] = "utf-8"

Este fallo está documentado en una issue de github https://github.com/ansible/ansible/issues/8644 aunque su resolución está prevista en una versión ‘mayor’ con lo que supongo que estará corregido en la rama 1.8.x mientras que en Debian stable estamos en la versión 1.7.2 a diciembre de 2015. Otra alternativa sería crear un virtual environment de python e instalar la versión que queramos, no lo he probado pero seguro que es posible.

 

 

git: eliminar fichero

Si estás usando git para gestionar las versiones de tu código y necesitas eliminar un fichero que ya no es necesario:

Este comando borra el fichero tanto de git como de tu sistema de archivos

git rm file.txt
git commit -m "delete file from disk and git"

Si necesitas mantener el fichero en tu sistema de ficheros pero no en git usa este comando

git rm --cached file.txt
git commit -m "delete file ONLY from git and keep at disk"

keynotopia: Free Twitter Bootstrap 3.0 UI Mockup Templates for Keynote and PowerPoint

Keynotopia es una empresa que se dedica a crear imagenes vectorizadas en alta resolución y las empaqueta en themes OpenOffice, Windows8 , Iphone, Ipad, web … en resumen son conjuntos de imágenes diseñadas para componer maquetas en keynote o powerpoint.
Es muy útil si quieres hacer prototipos de aplicaciones de una forma cómoda y standard, ya que al tener los elementos ya creados sólo permite colocar estos elementos pero no crear ninguno nuevo, aún así es interesante.

He intentando bajar de su página el set de diseño para bootstrap el framework de maquetación de twitter disponibel aquí http://keynotopia.com/bootstrap/ y como pago a cambio solicitar twitear su producto, me ha gustado la idea y he colgado el twit con las indicaciones de keynotopia. No he podido obtener el enlace y bueno… he trasteado un poco para descargarme el contenido.

Para obtener el fichero descargable he abierto firebug y he localizado el bloque html en el que se llama a la acción para twitear el producto
[shell]<div id=»pay-per-tweet»>
<a id=»tweetLink» href=»#»></a><br>
<a href=»#PAY»></a><p></p>
<p style=»font-weight:bold; font-size:14px; color:#B74726; text-align:center; margin-top:-25px;»>Clicking the orange button will pop-up a window where you can edit and confirm the tweet, and then the download button will be activated<br>
<br></p></div>[/shell]
El objeto que genera la acción es id=»tweetLink» así que lo siguiente es buscar código javascript que lo maneje:
[shell]$(document).ready(function(){
// Using our tweetAction plugin. For a complete list with supported
// parameters, refer to http://dev.twitter.com/pages/intents#tweet-intent
$(‘#tweetLink’).tweetAction({
text: ‘Check out Keynotopia: mobile and web UI #design templates for Keynote and PowerPoint. #UX #mockups’,
url: ‘http://keynotopia.com/’,
via: ‘amirkhella’,
related: ‘keynotopia’
},function(){
// When the user closes the pop-up window:
$(‘a.downloadButton’)
.addClass(‘active’)
.attr(‘href’,’https://www.e-junkie.com/ecom/gb.php?c=cart&i=1057391&cl=127351&ejc=2′);
});
});[/shell]

No hay que tener mucha idea para ver una pedazo de url ahí que suena bastante bien además del comentario de código( // When the user closes the pop-up window: ) , así que si la copias y la pegas en el navegador entrarás en el proceso de compra sin coste del producto que queríamos.

Habiendo cumplido las condiciones de twitear la información producto, me he buscado una forma de conseguir el theme sin esperar a que me contesten de Keynotopia.

SOAP __soapCall posible bug ? faltan parámetros

La petada del día de hoy ha sido con php 5.3 y el cliente de SOAP ( SoapClient::__soapCall() )

La historia es que estamos implementando un cliente para usar un webservice de un tercero y nos estaba petando siempre, por que su lado tampoco lo tienen muy apañao y nos devolvía unas trazas de java muy feas 😀

El caso es que al final me he liado a tracear las conexiones tcp para ver qué estabamos mandando y veía todo el rato que envíamos sólo un parámetro cuando tenían que ser dos. Después de volverme loco durante un rato, me ha funcionado haciendo la llamada directamente desde el objeto cliente.

Como esto es un carajal vamos a ver ejemplos reales ( he usado wireshark por que estoy perruno 😀 ) :
el script en php es este:

[shell]
<?php

try {
$wsdl = ‘http://localhost:8080/autenticacion/validateuser?WSDL’;

$params = array();
$params[‘authentication’] = SOAP_AUTHENTICATION_BASIC;
$params[‘login’] = «jorge» ;
$params[‘password’] = «senin» ;

$params[‘trace’] = true ;

$client = new SoapClient ( $wsdl ,$params ) ;

$validation = array ( ‘usuario’ => ‘pepe’, ‘password’ => ‘123456’ );

$result = $client->__soapCall ( ‘autenticar’ , $validation );

var_dump ( $result );

}

//gestion de excepciones
catch (Exception $e) {
print «SOAP Error: » . $e->getMessage();
print $client->__getLastResponse( );
}

?>
[/shell]

Devuelve:

[shell]
<?xml version=»1.0″ encoding=»UTF-8″?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=»http://schemas.xmlsoap.org/soap/envelope/» xmlns:ns1=»http://www.senin.org/autenticacion»>
<SOAP-ENV:Body>
<ns1:PeticionLogin/><param1>123456</param1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
[/shell]

Como veis falta un parámetro, falta el username, sólo me envía la password

pero si hago la llamada de esta forma :

[shell]
$result = $client->autenticar( $validation );
[/shell]

Funciona correctamente :

[shell]
<pre>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=»http://schemas.xmlsoap.org/soap/envelope/» xmlns:ns1=»http://www.senin.org/autenticacion»>
<SOAP-ENV:Body>
<ns1:PeticionLogin>
<ns1:usuario>jorge</ns1:Usuari>
<ns1:password>123456</ns1:Contrasenya>
</ns1:PeticionLogin>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</pre>
[/shell]

Si veis difiere como se envía el SOAP.

He encontrado esta entrada en un foro de drupal :

http://drupal.org/node/1191790

Those calls are not equal, because the arguments are passed differently. __soapCall() splits up the arguments array into separate parameters, while directly calling the operation method passes the arguments array as is. Looks like your server implements a document/wrapped parameter scheme, which is unfortunately not supported by the PHP SOAP client. You need to wrap the parameters yourself, your operation has only one complex data structure as parameter that contains the actual parameters as properties.

Y por hoy no está mal 😀

Fechas y horas usando la forma cómoda : » hour ago»

El comando date de linux es un poco… retorcido a veces y da pereza escribir una fecha concreta.

Por ello tenemos el modificador -d que nos hace la vida más fácil. Si queremos saber qué hora era hace una hora podemos ejecutar este comando :

[shell]
$ date -d ‘1 hour ago’
Mon Apr  2 13:22:04 CEST 2012
[/shell]

O quizás necesite saber qué día es la semana que viene.

[shell]
$date -d ‘1 next week’
Mon Apr  9 01:00:00 CEST 2012
[/shell]

Por supuesto podemos formatear la salida y preguntar qué dia de la semana será dentro de 22 días

[shell]
$date -d ’22 next day’ +’%A’
Tuesday
[/shell]

[SQLite] SQL error: near «EXISTS»: syntax error

llevo un rato dándo vueltas a este error para una secuencia de comandos sql para sqlite:

[shell]
sqlite> DROP TABLE IF EXISTS geolocation;
SQL error: near «EXISTS»: syntax error
[/shell]

Revisando la documentación la sintaxis es correcta :
http://sqlite.org/lang_droptable.html

SQL Drop table

… le he dado vueltas y más vueltas

… más vueltas

y he encontrado esto : http://www.sqlite.org/releaselog/3_3_0.html
[shell]
SQLite Release 3.3.0 On 2006 January 10 (3.3.0 alpha)

….
IF EXISTS and IF NOT EXISTS clauses on CREATE/DROP TABLE/INDEX.
….
[/shell]

Así que va a ser que mi base de datos no es version 3, vamos a ver… :

[shell]
sqlite> select sqlite_version();
2.8.17
[/shell]

… shit…

Ala para los que os haga falta

iconv-column-converter

Acabo de publicar mi primer proyecto en github

 

[shell]Es un pequeño script que he creado para normalizar un fichero.
Lo uso en volcados de datos como csv en los que la codificación de cada columna puede variar, mezclando columnas de utf8 con iso-8895-1 ( aka latin1 ).
A veces pasa con migraciones en las que la máquina de origen usa latin1 y la nueva máquina utf8 y mezclado con la ‘pericia’ de algunos desarrolladores provocan esta mezcla.

Con este script consigo un fichero uniforme para ser procesado por otra aplicación ( normalmente arcaica también 😀 )

Podeis descargarlo y verlo aqui[/shell]

SVN : Error detected while processing /usr/share/vim/vimrc

Otra de subversion :

[shell]
svn: Can’t open file ‘/var/lib/svn/hostingaldescubierto.com/db/txn-current-lock’: Permission denied
[/shell]

Esto es por que no hay permisos para modificar los ficheros, seguramente el propietario es root , pero estamos usando autenticación por apache, así le tenemos que dar permisos a www-data para que pueda commitear .

[shell]
chown -R www-data.www-data /var/lib/svn/hostingaldescubierto.com/
[/shell]