2015-06-29

pyspark en vanilla cpython

Estuve buscando cómo hacer para correr pyspark en cpython sin usar el ejecutable de pyspark, como para poder integrarlo en otras cosas. No encontré nada que explique cómo hacerlo en la web, pero encontré un tutorial para correr ipython notebook con pyspark y mirando las instrucciones hackié algo para lo que yo quiero. Lo probé con spark 1.3.0 y python 2.7. Acá el script:

import os
import sys


# Setup pythonpath
spark_home = '/path/to/spark'
os.environ["SPARK_HOME"] = spark_home
sys.path.insert(0, os.path.join(spark_home, 'python'))
sys.path.insert(0, os.path.join(spark_home, 'python/lib/py4j-0.8.2.1-src.zip'))


# Make local context
from pyspark import SparkContext

sc = SparkContext(master="local", appName="aure")


# Do something with spark to test that it works
spark_home = os.environ.get('SPARK_HOME', None)
text_file = sc.textFile(spark_home + "/README.md")

word_counts = text_file \
    .flatMap(lambda line: line.split()) \
    .map(lambda word: (word, 1)) \
    .reduceByKey(lambda a, b: a + b) \
    .sortBy(lambda p: p[1], ascending=False)
   
   
print word_counts.take(20)


Espero que les sirva,
Aureliano.

2015-06-23

Sandro en la consola

En los últimos días hice que sea posible correr la biblioteca de sandro de línea de comando y tenga una consola. Para correr la consola, usando todos los módulos de sandro, ponelo en el classpath (con sus dependencias) y corré:

$ java sandro.RhinoConsole

Eso abre una consola donde podés correr código, que es una consola como la de rhino pero customizada para poder importar los módulos de sandro usando penumbras.

js> var funMod = penumbras.loadModule("sandro/nadaMas/function")
js> funMod.isFun(5)
false
js> funMod.isFun(function(a) {} )
true


Pero esto no es todo, ¡también se pueden correr módulos de sandro desde la línea de comandos! Para eso, hay que poner los módulos en el classpath (en un jar o un directorio), aparte de sandro y sus dependencias, y correr:

$ java sandro.RhinoRunner my/custom/module param1 param2

Para que corran, el módulo tiene que exportar una función, que es la que llama el runner. Pueden mirar el módulo helloWorld (está en el proyecto de la biblioteca por ahora) para ver un ejemplo tonto:

define({
  javaPackages : "javaPackages",
  ary : "sandro/nadaMas/array"
}, function(m) {

  return function() {
    var out = m.javaPackages.java.lang.System.out
    out.println("Hello!")
    out.println(m.ary.fromArgs(arguments).join())
  }

})


Y si lo invocan de línea de comando, pasa esto:

$ java sandro.RhinoRunner helloWorld Hola Manola
Hello!
Hola,Manola


Usando esto, hice que los tests de la biblioteca corran de línea de comando así:

$ java sandro.RhinoRunner sandro/testRunner

Por último, saqué la dependencia de servlets del cargador de módulos, así que ahora no hace falta tener el API de servlets en el classpath para usar todas las cosas que no tienen que ver con la web.

Happy hacking,
Aureliano.

2015-06-17

eclipse@docker

Estuve scripteando un poquito, e hice que eclipse corra en un container de docker (base, ubuntu:trusty), con las cosas que necesito para desarrollar sandro

Primero hice un dockerfile bastante trivial:

FROM ubuntu:trusty
RUN apt-get update && apt-get install -y \
  git \
  mercurial \
  default-jdk


con su correspondiente .dockerignore

dockerfile
.dockerignore


en un directorio que nombré docker

Después hice una imagen con ese container (a la que llamé, sandro:base).

$ docker build -t sandro:base docker

Y después vino la parte complicada.

Decidí correr el eclipse en volumenes afuera del container, con la idea de que quizás sea una buena idea inyectarlo en muchos distintos y poder instalar fácilmente plug-ins y esas cosas y que siga andando todo cuando haga otros containers. Para eso hice 4 directorios:

  • eclipse: donde puse un eclipse luna
  • workspace: donde va el workspace del eclipse
  • devel: donde pongo todo mi código
  • apache-tomcat-7.0.62: acá puse un tomcat bajado de apache.org
 Usando esa estructura hice 2 scripts:
  • dev.sh corre cualquier programa en un container nuevo, setupeando todo para tener un ambiente razonable para laburar.
  • eclipse.sh arranca eclipse usando dev.sh
Primero les muestro eclipse.sh

#!/usr/bin/env bash 

./dev.sh $1 eclipse/eclipse -data /workspace 

Le pasás por parámetro la imagen que querés usar para arrancarlo, y usa como workspace el directorio workspace que les conté más arriba.

Y ahora, la posta. dev.sh

#!/usr/bin/env bash

xhost +SI:localuser:root
ID=$( docker run \
  -d --name sandro-dev -h sandro-dev \
  -e SSH_AUTH_SOCK=$SSH_AUTH_SOCK -v $(dirname $SSH_AUTH_SOCK):$(dirname $SSH_AUTH_SOCK) \
  -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e GIT_SSH=/usr/bin/ssh \
  -v `pwd`/devel:/devel -v `pwd`/eclipse:/eclipse -v `pwd`/workspace:/workspace -v `pwd`/apache-tomcat-7.0.62:/tomcat \
  -p 127.0.0.1:8080:8080 \
  $@ )
docker wait $ID
docker rm $ID


Mejor voy línea por línea porque es un bardo

  1. xhost +SI:localuser:root habilita al container a poner aplicaciones en la GUI (las apps de los containers corren como root).
  2. ID=$( docker run \ arranco el container y guardo su id
  3. -d --name sandro-dev -h sandro-dev \ hace que el container corra desattacheado y setea nombre y hostname a sandro-dev para hacerme la vida más fácil
  4. -e SSH_AUTH_SOCK=$SSH_AUTH_SOCK -v $(dirname $SSH_AUTH_SOCK):$(dirname $SSH_AUTH_SOCK) \ setupea el forwardeo del agente de ssh. Puede resultar útil si quieren pushear código vía ssh sin usar passwords
  5. -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \ Comparte el display del desktop con el container
  6. -e GIT_SSH=/usr/bin/ssh \ para que si usan eclipse con git use el agente de ssh
  7. -v `pwd`/devel:/devel -v `pwd`/eclipse:/eclipse -v `pwd`/workspace:/workspace -v `pwd`/apache-tomcat-7.0.62:/tomcat \ monta todos los directorios que quedan afuera del container
  8. -p 127.0.0.1:8080:8080 \ forwardea el puerto 8080 (donde va a correr el tomcat de desarrollo) a localhost. Lo bindeo a 127.0.0.1 para que no se puedan conectar desde afuera.
  9. $@ ) recibe más parámetros para docker run, incluyendo los comandos para correr y el nombre de la imagen a usar
  10. docker wait $ID espera a que termine de correr el container
  11. docker rm $ID lo borra
Espero que les resulte útil, y espero mejoras y críticas,
Aureliano.