27 mar. 2016

Ejecutar una prueba de unittest en Python con un contenedor Docker.

En este artículo practicamente se hará lo mismo que el artículo anterior, pero se creará un archivo donde se define una clase la cual hará las pruebas unitarias.

La parte de pruebas unitarias se basa de un post anterior que se llama Pruebas unitarias con unittest en Python.

Los artículos anteriores sobre docker son:
  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.
  11. Compartir imagenes Docker por medio de archivos tar.
  12. Crear un registro de imagenes Docker privado.
  13. Usar Anaconda desde un contenedor Docker.
  14. Crear un entorno de Integración y Despligue continue con Docker para node.js.
  15. Usar Jupyter Notebook desde un contenedor Docker.
  16. Ejecutar una prueba de doctest con un contenedor Docker.

Ahora se tendrá los siguientes archivos en el directorio pruebas-doctest:

pruebas-doctest
├── Dockerfile
├── raizcuadrada.py
├── raizcuadrada_test.py
└── raizcuadrada.txt

El Dockerfile, raizcuadrada.py y raizcuadrada.txt son los mismos del artículo anterior.

El archivo raizcuadrada_test.py tiene lo siguiente:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Se importa el módulo unittest y math
import unittest
#Se importa la funcion Raiz del modulo raizcuadrada
from raizcuadrada import Raiz

class RaizTest(unittest.TestCase):

    def test_Raiz(self):
        """Test para la raiz de nueve que devuelve 3 que debe pasar."""
        self.assertEqual(3, Raiz(9))

    def test_zero(self):
        """Test para la raiz de 0 que devuelve 0, que debe pasar."""
        self.assertEqual(0, Raiz(0))

        
    def test_negative(self):
        """Test para la raiz de un número negativo, que debe fallar."""
        # Este debe devolver un ValueError, pero se espera un IndexError.
        self.assertRaises(IndexError, Raiz(-10))


if __name__ == '__main__':
    #Se ejecuta la prueba unitaria
    unittest.main()


Ahora se reconstruye  la imagen de Docker:

docker build -t pruebas-doctest .
Sending build context to Docker daemon  7.68 kB
Step 1 : FROM python:3.4
 ---> c40d327867e9
Step 2 : MAINTAINER Ernesto Crespo
 ---> Using cache
 ---> 3b1aced33b5e
Step 3 : WORKDIR /app
 ---> Using cache
 ---> 7dd09842cf61
Step 4 : COPY . /app
 ---> 842cd3bd051f
Removing intermediate container 140eaaf7935f
Successfully built 842cd3bd051f


Y se ejecuta la prueba:

docker run pruebas-doctest python raizcuadrada_test.py
.E.
======================================================================
ERROR: test_negative (__main__.RaizTest)
Test para la raiz de un número negativo, que debe fallar.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "raizcuadrada_test.py", line 25, in test_negative
    self.assertRaises(IndexError, Raiz(-10))
  File "/app/raizcuadrada.py", line 22, in Raiz
    raise ValueError("a debe ser >= 0")
ValueError: a debe ser >= 0

----------------------------------------------------------------------
Ran 3 tests in 0.002s

FAILED (errors=1)


La está primera prueba se preparo para que fallara, ahora se comenta el método de prueba negativa, se reconstruye la imagen y se vuelve a ejecutar:

docker build -t pruebas-doctest .
Sending build context to Docker daemon  7.68 kB
Step 1 : FROM python:3.4
 ---> c40d327867e9
Step 2 : MAINTAINER Ernesto Crespo
 ---> Using cache
 ---> 3b1aced33b5e
Step 3 : WORKDIR /app
 ---> Using cache
 ---> 7dd09842cf61
Step 4 : COPY . /app
 ---> 609702415974
Removing intermediate container e2174beb4f7c
Successfully built 609702415974

docker run pruebas-doctest python raizcuadrada_test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK



Se ejecutaron 2 test y pasaron. 

Ya con esta imagen de Docker se puede reusar en varios computadores teniendo el mismo ambiente de desarrollo. 



Ejecutar una prueba de doctest con un contenedor Docker.


Ahora se mostrará como usar un contenedor de Docker para hacer pruebas doctest, este artículo se basa en un post anterior del blog llamado Separar código de pruebas de la documentación (doctest,2da parte).


Los artículos anteriores sobre docker son:
  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.
  11. Compartir imagenes Docker por medio de archivos tar.
  12. Crear un registro de imagenes Docker privado.
  13. Usar Anaconda desde un contenedor Docker.
  14. Crear un entorno de Integración y Despligue continue con Docker para node.js.
  15. Usar Jupyter Notebook desde un contenedor Docker.


Se tendrán 3 archivos en un directorio que se llamará pruebas-doctest con lo siguiente:

pruebas-doctest
├── Dockerfile
├── raizcuadrada.py
└── raizcuadrada.txt

El archivo Dockerfile contendrá lo siguiente:

FROM python:3.4
MAINTAINER Ernesto Crespo

WORKDIR /app
COPY . /app

Se usará python 3.4, el mantenedor es Ernesto Crespo, el directorio de trabajo será app y se copiará todo lo que está en el directorio al directorio de trabajo.

Se tiene el archivo raizcuadrada.py con lo siguiente:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Se importa el módulo math para calcular la raiz cuadrada.
"""
import math
#Función raiz cuadrada.
def Raiz(a):
    """Si a es mayor o igual a cero se calcula la raiz cuadrada"""
    if a >= 0:
        return math.sqrt(a)
    #Si es menor a cero se genera una excepción donde se informa que a debe ser mayor o igual a cero.
    else:
        raise ValueError("a debe ser >= 0")
if __name__ == '__main__':
    #Se importa el módulo doctest
    import doctest
    #Se realiza la prueba al archivo raizcuadra.txt
    doctest.testfile("raizcuadrada.txt")



Y el último de los archivos es raizcuadrada.txt el cual tendrá las pruebas de doctest:
Modulo raiz cuadrada
=====================
Usando  'raizcuadrada'
------------------------------
Primero se importa la función:
>>> from raizcuadrada import Raiz
Ejemplos de calculo de raiz cuadrada:
>>> Raiz(4)
2.0
>>> Raiz(9)
3.0
>>> Raiz(25)
5.0
>>> Raiz(0)
0.0
>>> Raiz(16)
5.0
>>> Raiz(-1)
Traceback (most recent call last):
...
ValueError: a debe ser >= 0


El archivo tiene un error intencional en el cálculo de la raíz cuadrada de 16 que debe dar 4 y se coloco que da 5.


Ahora se construye la imagen con nombre pruebas-doctest:

docker build -t pruebas-doctest .
Sending build context to Docker daemon  5.12 kB
Step 1 : FROM python:3.4
3.4: Pulling from library/python
fdd5d7827f33: Downloading 11.35 MB
fdd5d7827f33: Pull complete 
a3ed95caeb02: Pull complete 
0f35d0fe50cc: Pull complete 
7b40647e93b7: Pull complete 
ce5207842c4c: Pull complete 
da7994e536a7: Pull complete 
09482b8dda8a: Pull complete 
5ba79222c836: Pull complete 
Digest: sha256:8bcba46a3dbf4803c80074c0e543d98eeb3cb4f9cc35ff52f88c53cc0a1c30c3
Status: Downloaded newer image for python:3.4
 ---> c40d327867e9
Step 2 : MAINTAINER Ernesto Crespo
 ---> Running in de81df2565f3
 ---> 3b1aced33b5e
Removing intermediate container de81df2565f3
Step 3 : WORKDIR /app
 ---> Running in f1901c2490d7
 ---> 7dd09842cf61
Removing intermediate container f1901c2490d7
Step 4 : COPY . /app
 ---> 788ad6d153ed
Removing intermediate container b32ba65862d9
Successfully built 788ad6d153ed


Ahora se ejecuta la prueba pasando python -m doctest -v raizcuadrada.txt:

docker run pruebas-doctest python -m doctest -v raizcuadrada.txt
Trying:
    from raizcuadrada import Raiz
Expecting nothing
ok
Trying:
    Raiz(4)
Expecting:
    2.0
ok
Trying:
    Raiz(9)
Expecting:
    3.0
ok
Trying:
    Raiz(25)
Expecting:
    5.0
ok
Trying:
    Raiz(0)
Expecting:
    0.0
ok
Trying:
    Raiz(16)
Expecting:
    5.0
**********************************************************************
File "raizcuadrada.txt", line 23, in raizcuadrada.txt
Failed example:
    Raiz(16)
Expected:
    5.0
Got:
    4.0
Trying:
    Raiz(-1)
Expecting:
    Traceback (most recent call last):
    ...
    ValueError: a debe ser >= 0
ok
**********************************************************************
1 items had failures:
   1 of   7 in raizcuadrada.txt
7 tests in 1 items.
6 passed and 1 failed.
***Test Failed*** 1 failures.


El resultado es que se logró pasar 6 pruebas y una no paso, se arregla el valor que debe devolver en el archivo raizcuadrada.txt y se vuelve a ejecutar la construcción y ejecución :

docker build -t pruebas-doctest .
Sending build context to Docker daemon 4.608 kB
Step 1 : FROM python:3.4
 ---> c40d327867e9
Step 2 : MAINTAINER Ernesto Crespo
 ---> Using cache
 ---> 3b1aced33b5e
Step 3 : WORKDIR /app
 ---> Using cache
 ---> 7dd09842cf61
Step 4 : COPY . /app
 ---> 47a9b0467413
Removing intermediate container 8a375d3abc0c
Successfully built 47a9b0467413

docker run pruebas-doctest python -m doctest -v raizcuadrada.txt
Trying:
    from raizcuadrada import Raiz
Expecting nothing
ok
Trying:
    Raiz(4)
Expecting:
    2.0
ok
Trying:
    Raiz(9)
Expecting:
    3.0
ok
Trying:
    Raiz(25)
Expecting:
    5.0
ok
Trying:
    Raiz(0)
Expecting:
    0.0
ok
Trying:
    Raiz(16)
Expecting:
    4.0
ok
Trying:
    Raiz(-1)
Expecting:
    Traceback (most recent call last):
    ...
    ValueError: a debe ser >= 0
ok
1 items passed all tests:
   7 tests in raizcuadrada.txt
7 tests in 1 items.
7 passed and 0 failed.
Test passed.


Ahora si se logró pasar todas las pruebas de doctest.



26 mar. 2016

Usar Jupyter Notebook desde un contenedor de Docker

Jupyter Notebook es una aplicación web que permite crear y compartir documentos que  contienen código, gráficos y texto. Sus usos incluyen limpieza y transformación de datos, simulación numérica, modelado estadistico, machine learning y mucho más. Más información lo pueden ver en este enlace.

La idea es ejecutar jupyter notebook desde un contenedor docker donde se guardará los archivos generados en el directorio definido por medio de volumen.

Los artículos anteriores sobre docker son:
  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.
  11. Compartir imagenes Docker por medio de archivos tar.
  12. Crear un registro de imagenes Docker privado.
  13. Usar Anaconda desde un contenedor Docker.
  14. Crear un entorno de Integración y Despligue continue con Docker para node.js.

Existe varias imagenes de Docker de la gente de jupyter, la que se va a usar es la de jupyter notebook.

Para ejecutar el contenedor ejecutamos lo siguientes:

$docker run --rm -it -p 8888:8888 -v "$(pwd):/notebooks" jupyter/notebook

Al ejecutar el comando se tiene lo que muestra la siguiente imagen:

El puerto externo al contenedor será el 8888, igual que el interno, el volumen se maneja desde el directorio donde se ejecuta el comando anterior. 

Desde un navegador se abre el siguiente enlace: http://localhost:8888/ .


Se crea un documento donde se realiza una serie de instrucciones de python y se salva con nombre prueba-python:


Al ejecutar un ls -l en el directorio donde se inicio el contenedor se tiene el archivo prueba-python.ipynb:

 ls -l notebooks/
total 4
-rw-r--r-- 1 root root 1390 mar 26 20:04 prueba-python.ipynb

Por medio de la opción de volumen se está compartiendo el directorio notebooks del contenedor en el equipo anfitrion.

Crear un entorno de Integración y Despligue continue con Docker para node.js

Continuando con los artículos de Docker, está vez se muestra como tener un entorno de integración continua CI y de despliegue continuo CD con Docker para una aplicación web con node.js.

Los artículos anteriores sobre Docker son:
  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.
  11. Compartir imagenes Docker por medio de archivos tar.
  12. Crear un registro de imagenes Docker privado.
  13. Usar Anaconda desde un contenedor Docker.
Se creo un directorio llamado nodejs que contendrá lo siguiente:

nodejs
├── app.js
├── Dockerfile
└── package.json

Dentro del directorio se tiene el archivo javascript llamado app.js, se tiene el archivo Dockerfile y el otro el package.json. 

El archivo app.js contiene lo siguiente:

// se crea la instancia de http
var http = require('http');
// Se crea la instancia del servidor donde se define el tipo del Content-type como text/plain
//Devuelve un hola mundo particular.
var server = http.createServer(function (request, response) {
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.end("Hola mundo desde un contenedor Docker con nodejs.");
});
//El servidor escuchará el puerto 8000.
server.listen(8000);
//se devuelve un mensaje en la consola que se ejecuta el servidor web.
console.log("Server running at http://127.0.0.1:8000/");

El archivo package.json contiene lo siguiente:
{
    "name": "hola-mundo",
    "description": "hola mundo",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "express": "3.x"

    },
    "scripts": {"start": "node app.js"}

}

Se le da el nombre de la aplicación, su descripción, la versión, que es privada y en las dependencias se instala express la versión 3.x, por último el script inicia la aplicación app.js.

Ahora se explicará el archivo Dockerfile:

FROM google/nodejs
MAINTAINER Ernesto Crespo <ecrespo@gmail.com>
WORKDIR /app
ADD package.json /app/
RUN npm install
ADD . /app
EXPOSE 8000
CMD []
ENTRYPOINT ["/nodejs/bin/npm", "start"]


Se descargará nodejs del repositorio que maneja google, se define el mantenedor de la imagen, el directorio de trabajo es /app, se agrega el archivo package.json al directorio de trabajo, se ejecuta npm install, se agrega el directorio app que se encuentra en la estructura de directorio ya explicada, se expone el puerto 8000, CMD se pasa [] y el entrypoint inicia npm. .

Para construir la imagen se ejecuta:

docker build -t nodejs_img .

Al ejecutar docker images se tiene la imagen nodejs_img:
docker images 
REPOSITORY                    TAG                 IMAGE ID            CREATED              SIZE
nodejs_img                    latest              38d1802c8726        About a minute ago   501.6 MB


Ahora se ejecuta el contenedor:

docker run -p 8000:8000 nodejs_img

> hola-mundo@0.0.1 start /app
> node app.js

Server running at http://127.0.0.1:8000/


Al abrir el navegador en esa dirección se tiene:


Se puede modificar el archivo app.js agregando lo siguiente:

var http = require('http');
var server = http.createServer(function (request, response) {
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.end("Hola mundo desde un contenedor Docker con nodejs, prueba modificando al vuelo");
});

server.listen(8000);

console.log("Server running at http://127.0.0.1:8000/");

Se detiene el contenedor y se vuelve a ejecutar:

docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ee8395c6c1b0        nodejs_img          "/nodejs/bin/npm star"   4 minutes ago       Up 4 minutes        0.0.0.0:8000->8000/tcp   clever_shirley

docker stop ee8395c6c1b0
ee8395c6c1b0


Para que se refleje los cambios del archivo app.js se reconstruye la imagen del docker y luego se vuelve a iniciar el contenedor:

docker build -t nodejs_img .
docker run -p 8000:8000 -v "$PWD":/app nodejs_img 

> hola-mundo@0.0.1 start /app
> node app.js


Server running at http://127.0.0.1:8000/

Y al abrir el navegador en el url:

Se puede crear script para parar, borrar y reconstruir las imagenes haciendo más fácil el proceso de integración continua y despliegue continuo.

Más información la pueden conseguir en el artículo: Docker en la ejecución de test de integración en NodeJS

Usar Anaconda desde un contenedor Docker

Continuando con artículos relacionados con Docker. Está vez se mostrará como correr Anaconda desde una imagen Docker.


A continuación les dejo los artículos anteriores:

  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.
  11. Compartir imagenes Docker por medio de archivos tar.
  12. Crear un registro de imagenes Docker privado.

Lo primero que se estarán preguntando es, ¿Qué es Anaconda?. 

La respuesta se la pueden conseguir en el enlace oficial del sitio continuum:

Anaconda es un manejador de paquetes (libre y fácil de instalar),manejo de entorno, distribución de Python, y una colección de más de 720 paquetes opensource con soporte comunitario. Además se puede instalar más de mil paquetes con el comando conda install <paquete>, funciona en Linux, Windows y OSX.  Anaconda es la herramienta hecha para cientificos de datos.

¿Quienes más usan anaconda?
  • Cientificos de Datos
  • Desarrolladores
  • Ingenieros de Datos
  • DevOps
  • Analistas de negocios
El procedimiento para usar anaconda lo explican en este enlace.

Las imagenes existentes de anaconda la pueden ver en este enlace.

Para ver las imagenes de la gente de continuum se realiza una busqueda con docker:

$docker search continuumio

NAME                                   DESCRIPTION                                           STARS     OFFICIAL   AUTOMATED
continuumio/anaconda                 Powerful and flexible python distribution    27                   [OK]
continuumio/miniconda                Powerful and flexible package manager     14                   [OK]
continuumio/anaconda3                                                                               10                   [OK]
continuumio/miniconda3                                                                                5                    [OK]
continuumio/memex_explorer      memex explorer app                                   1                    
continuumio/solr                          solr 10.4.2 + tika                                       0                    
continuumio/tika                          Tika 1.9                                                     0                    
continuumio/binstar-build-linux64                                                                  0                    [OK]
continuumio/kibana                                                                                       0                    
continuumio/imagecat                   Docker Container for ImageCat                0                    
continuumio/banana                                                                                      0

Luego se bajará la imagen miniconda:

$ docker pull continuumio/miniconda

Using default tag: latest
latest: Pulling from continuumio/miniconda
a3ed95caeb02: Pull complete 
79362e2488a1: Pull complete 
41938770486e: Pull complete 
1c66b99d17cb: Pull complete 
33e1cf31bc39: Pull complete 
Digest: sha256:5d27e59a93068184fc6dd63043746ad35aa15dd2862ff0babd391bc3c05a5fc4
Status: Downloaded newer image for continuumio/miniconda:latest

Ahora se puede iniciar un contenedor a partir de la imagen que se descargó:
$ docker run -t -i continuumio/miniconda /bin/bash
root@f7115572fad4:/# 

Se prueba que conda está instalado en ese contenedor:

ernesto@jewel:~/dockerfiles$ docker run -t -i continuumio/miniconda /bin/bash
root@f7115572fad4:/# conda info
Current conda install:

             platform : linux-64
        conda version : 3.19.0
  conda-build version : not installed
       python version : 2.7.11.final.0
     requests version : 2.9.0
     root environment : /opt/conda  (writable)
  default environment : /opt/conda
     envs directories : /opt/conda/envs
        package cache : /opt/conda/pkgs
         channel URLs : https://repo.continuum.io/pkgs/free/linux-64/
                        https://repo.continuum.io/pkgs/free/noarch/
                        https://repo.continuum.io/pkgs/pro/linux-64/
                        https://repo.continuum.io/pkgs/pro/noarch/
          config file : None
    is foreign system : False



Ahora se instalará scipy vía el comando conda:
root@f7115572fad4:/# conda install scipy
Fetching package metadata: ....
Solving package specifications: ....................
Package plan for installation in environment /opt/conda:

The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    libgfortran-3.0            |                0         261 KB
    mkl-11.3.1                 |                0       121.2 MB
    openssl-1.0.2g             |                0         3.2 MB
    sqlite-3.9.2               |                0         3.9 MB
    numpy-1.10.4               |           py27_1         6.0 MB
    requests-2.9.1             |           py27_0         605 KB
    setuptools-20.3            |           py27_0         452 KB
    wheel-0.29.0               |           py27_0          81 KB
    conda-4.0.5                |           py27_0         185 KB
    pip-8.1.1                  |           py27_0         1.5 MB
    scipy-0.17.0               |      np110py27_2        30.1 MB
    ------------------------------------------------------------
                                           Total:       167.3 MB

The following NEW packages will be INSTALLED:

    libgfortran: 3.0-0             
    mkl:         11.3.1-0          
    numpy:       1.10.4-py27_1     
    scipy:       0.17.0-np110py27_2

The following packages will be UPDATED:

    conda:       3.19.0-py27_0 --> 4.0.5-py27_0      
    openssl:     1.0.2d-0      --> 1.0.2g-0          
    pip:         7.1.2-py27_0  --> 8.1.1-py27_0      
    requests:    2.9.0-py27_0  --> 2.9.1-py27_0      
    setuptools:  18.8.1-py27_0 --> 20.3-py27_0       
    sqlite:      3.8.4.1-1     --> 3.9.2-0           
    wheel:       0.26.0-py27_1 --> 0.29.0-py27_0     

Proceed ([y]/n)? y

Otra opción es bajar continuumio/anaconda, que tiene la paqueteria base:

$ docker pull continuumio/anaconda

Y se ejecuta el contenedor:
ernesto@jewel:~/dockerfiles$ docker run -t -i continuumio/anaconda /bin/bash
root@f7115572fad4:/#


25 mar. 2016

Descarga de documentos (Informes de gestión del 2015) de la página web de la Asamblea Nacional con Python

Retomando los artículos sobre webscraping (pueden visitarlos en el siguiente enlace).


Se tiene la página de la Asamblea Nacional,  donde se alojan las memorias y cuentas del Ejecutivo Nacional, pueden visitar el sitio en el siguiente enlace.

El url es: http://www.asambleanacional.gob.ve//documento/show2/id/64 .

A continuación se muestra una imagen de la página ya citada:




Alguno de los enlaces son archivos en pdf y otros archivos .tar.

La idea es usar request y BeautifulSoup para primero abrir la página, luego extraer la información, llegar a los enlaces y bajar los archivos.

El repositorio de github del script se encuentra en el siguiente enlace.

El código se muestra a continuación:

#!/usr/bin/python3



import requests

from bs4 import *

import sys 

import wget




#Entrada del url y del patrón a buscar
url  = input('Enter URL -> ')

pattern = input('Enter search pattern-> ')


#Se lee la página web
html = requests.get(url)


#Se define el directorio donde se descargará los archivos
dir_download = "./download/"




#Si en la página se tiene bad request se sale de la aplicación
if html.text.find("400 Bad Request") != -1:

 print ("Bad Request")

 sys.exit()


#Se instancia BeautifulSoup con el texto de la página web
soup = BeautifulSoup(html.text)


#Se genera una lista de los tags 'a' que tiene la página
tags = soup('a')


#Se recorre los tags buscando si existe el tag href
#Si no existe se busca en el siguiente tag 'a'
#se crea el url a descargar.
#Y se intenta descargar el archivo
for tag in tags:

 url_path = tag.get('href',None)

 text = str(url_path)

 if text.find(pattern) == -1: continue

 domain = url.split("http://")[1].split("/")[0]

 urldownload = "http://" + domain + text

 print ("Retrieve: {0},{1}".format(tag.contents[0],urldownload))

 file =  text.split("/")[-1]

 path_and_file = dir_download + file

 try:

  r = requests.get(urldownload)

  with open(path_and_file, "wb") as f:

   f.write(r.content)

 except ConnectionError:

  print("Can't download file: {0}".format(file))

 except HTTPError:

  print("Can't download file: {0}".format(file))

 f.close()




Para ejecutar el programa se tiene:

./pyurldownload_file.py 
Enter URL -> http://www.asambleanacional.gob.ve/documento/show2/id/64
Enter search pattern-> documentos

Al final de la ejecución del script se tendrá todos los archivos .tar y .pdf de la memoria y cuenta del Poder Ejecutivo del año 2015. 

En la siguiente figura se muestra el directorio download con los primeros archivos descargados:
Y en la siguiente figura se muestra uno de los archivos abierto con evince:


Es necesario resaltar que el formato pdf es un crimen usarlo a la hora de análisis de datos ya que es posible por medio de humanos, los programas les cuenta leer contenido de un pdf, aunque se puede, se pierde información. 

Es necesario que estos reportes de las instituciones y ministerios sean colocados como API Rest Ful enfocado a datos (json o xml) directamente de los portales de dichas instituciones. 

Esto facilitaría el análisis de la información de dichos reportes. 

En un futuro el script manejara hilos a fin de acelerar el proceso de descarga de los archivos.


Otro ejemplo de webscraping lo pueden encontrar en este enlace.

25 feb. 2016

Crear un registro de imagenes Docker privado.

Por ahí he leído toda la infraestructura que es necesaria insalar para tener un sistema de registro privado de imagenes de Docker.

Pero no, usemos Docker!!!


Con esta idea se puede bajar una imagen del registro de Docker del siguiente enlace.

Antes de continuar les dejaré la lista de artículos sobre Docker que he tocado en el blog:

  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.
  11. Compartir imagenes Docker por medio de archivos tar.
Lo primero que se hará es bajar la imagen Docker del registro, se tiene la versión oficial que es la 2 o la última.

$docker pull registry:2
ó
$docker pull registry

Se inicia el contenedor en el puerto 5000:

$ docker run -d -p 5000:5000 registry:2 
3c0719746d75f46220328c08209b3e716c8e883ad6f3df7bbae0d70e50656a45

Para verificar que el registro está corriendo se prueba con curl conectarse a localhost al puerto 5000 a v2/:
$ curl -i http://localhost:5000/v2/
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
X-Content-Type-Options: nosniff
Date: Thu, 25 Feb 2016 18:40:25 GMT


Ahora se puede probar subir una imagen al sistema privado de registro, se prueba con busybox:

Se crea un tag:
$docker tag busybox localhost:5000/busy

Se sube la imagen:

$ docker push localhost:5000/busy
The push refers to a repository [localhost:5000/busy]
5f70bf18a086: Pushed 
9508eff2c687: Pushed 
latest: digest: sha256:b58c00d636b25f40fc7605b1b807af81c1a79a7bbb2179b4753b9dc7e0d1dcd7 size: 711

Para poder acceder de manera insegura al registro privado se tiene que modificar el archivo /etc/default/docker y agregar la siguiente línea (tomar en cuenta que el contenedor está corriendo en localhost):

DOCKER_OPTS="--insecure-registry localhost:5000"

Se reinicia el servicio de docker:

# service docker restart

Para más información de las opciones del registro de Docker pueden revisar el siguiente enlace.

Para revisar las imagenes almacenadas en el sistema de registro privado se ejecuta:
curl http://localhost:5000/v2/_catalog
{"repositories":["busy"]}



El catalogo muestra que se tiene la imagen busy.

Se puede crear otra tag de busybox con nombre busy1 y se sube al servidor:

$docker tag busybox localhost:5000/busy1

$ docker push localhost:5000/busy1
The push refers to a repository [localhost:5000/busy1]
5f70bf18a086: Mounted from busy 
9508eff2c687: Mounted from busy 
latest: digest: sha256:b58c00d636b25f40fc7605b1b807af81c1a79a7bbb2179b4753b9dc7e0d1dcd7 size: 711

Al volver a consultar el catalogo se tiene dos imagenes:
$curl http://localhost:5000/v2/_catalog
{"repositories":["busy","busy1"]}

Cada imagen tiene un manifiesto:

$curl http://localhost:5000/v2/busy1/manifests/latest

$ curl http://localhost:5000/v2/busy1/manifests/latest
{
   "schemaVersion": 1,
   "name": "busy1",
   "tag": "latest",
   "architecture": "amd64",
   "fsLayers": [
      {
         "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
      },
      {
         "blobSum": "sha256:d7e8ec85c5abc60edf74bd4b8d68049350127e4102a084f22060f7321eac3586"
      }
   ],
   "history": [
      {
         "v1Compatibility": "{\"architecture\":\"amd64\",\"config\":{\"Hostname\":\"ea7fe68f39fd\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"sh\"],\"Image\":\"5c5fb281b01ee091a0fffa5b4a4c7fb7d358e7fb7c49c263d6d7a4e35d199fd0\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"container\":\"f63d86f7f85b3207532327b6e484bf09d8a0d1a0979cf7bdce1bd5268666fdd3\",\"container_config\":{\"Hostname\":\"ea7fe68f39fd\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"sh\\\"]\"],\"Image\":\"5c5fb281b01ee091a0fffa5b4a4c7fb7d358e7fb7c49c263d6d7a4e35d199fd0\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"created\":\"2015-12-08T18:31:51.481948133Z\",\"docker_version\":\"1.8.3\",\"id\":\"a997905216262e309de0dccc4c8ed39ee475a9d0e6b3f3c3a40b4ccf28af9b15\",\"os\":\"linux\",\"parent\":\"3d030bd4e34f5ed0b05de21a56503d80881fb1464afdde1c06a2b39c59260a22\"}"
      },
      {
         "v1Compatibility": "{\"id\":\"3d030bd4e34f5ed0b05de21a56503d80881fb1464afdde1c06a2b39c59260a22\",\"created\":\"2015-12-08T18:31:50.979824705Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) ADD file:c295b0748bf05d4527f500b62ff269bfd0037f7515f1375d2ee474b830bad382 in /\"]}}"
      }
   ],
   "signatures": [
      {
         "header": {
            "jwk": {
               "crv": "P-256",
               "kid": "FO3A:MIWL:JVJW:5O62:N7RK:GZXL:ACGC:WRUQ:PM4P:FVDL:PBAQ:X3IG",
               "kty": "EC",
               "x": "8eTT88WGU5NVLCrp5qGa4cO_nCo00e1L-eNLKF_0eeE",
               "y": "QwgEYEkJDxz4vihT3Mc6OitZ9uraF_TwbfpvZm72dJ8"
            },
            "alg": "ES256"
         },
         "signature": "LkmuupCii3CgtJKkKbasvkKc1jo7V0rZP9k4EFXuVMQL08-7n8s8TWzNB_Wx8oTv4qMb-Bpqhv3A2jdemu6eSA",
         "protected": "eyJmb3JtYXRMZW5ndGgiOjIyMTQsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNi0wMi0yNVQxOToxNjoxNFoifQ"
      }
   ]
}


Para listar todos los tags de una imagen se tiene:
$ curl http://localhost:5000/v2/busy1/tags/list
{"name":"busy1","tags":["latest"]}
$ curl http://localhost:5000/v2/busy/tags/list
{"name":"busy","tags":["latest"]}


Se puede hacer un pull del sistema de registro local para verificar que la imagen está actualizada:

$ docker pull localhost:5000/busy1
Using default tag: latest
latest: Pulling from busy1
Digest: sha256:b58c00d636b25f40fc7605b1b807af81c1a79a7bbb2179b4753b9dc7e0d1dcd7
Status: Image is up to date for localhost:5000/busy1:latest


Para más información del despliegue del sistema de registro pueden revisar el siguiente enlace.

24 feb. 2016

Compartir imagenes Docker por medio de archivos tar

Uno de los puntos más importantes a la hora de trabajar con Docker es el compartir  imagenes Docker aparte de usar Docker Hub.

Se tiene la exportación e importación de imagenes como opción almacenando y extrayendo a partir de archios tar.

Se tienen los artículos anteriores sobre Docker:

  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.
  10. Importar un contenedor Docker en Python.

Lo primero es ver que contenedores se tienen ejecutandose en el equipo:

$docker ps 
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                                                                    NAMES
b0c1163d1668        gitlab/gitlab-ce:latest   "/assets/wrapper"        4 weeks ago         Up 4 hours          0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8022->22/tcp           gitlab
b4d3c96f6dc9        jenkins                   "/bin/tini -- /usr/lo"   4 weeks ago         Up 4 hours          0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp, 0.0.0.0:8122->22/tcp   jenkins


Se tienen dos contenedores ejecutandose, uno de gitlab y otro de jenkins.

Se realizará respaldo del contenedor con gitlab usando el comando docker export, pasando el id del contenedor de gitlab que es b0c1163d1668:

$docker export b0c1163d1668 > gitlab.tar

Al ejecutar ls se tiene el archivo gitlab.tar:

ls -l
total 2201820
-rw-r--r-- 1 ernesto ernesto 1409662976 feb 24 16:15 gitlab.tar


Para usar la imagen a partir del archivo tar se importa la imagen: 

$ docker import - gitlab2 < gitlab.tar
sha256:020ea830b267080ce092f42b1b0f1a2d520b21b8a3393696f5271f42e4bd8d79

El nombre de la imagen es gitlab2, ahora se lista las imagenes que se tienen en el equipo:

$ docker images | grep gitlab
gitlab2                        latest              020ea830b267        About a minute ago   1.344 GB
gitlab/gitlab-ce               latest              db1c29be1030        6 weeks ago          1.326 GB
sameersbn/gitlab               latest              47d53c4a820a        10 weeks ago         675.7 MB

Si se quiere compartir la imagen con alguien,  se puede subir el archivo tar a un servidor web y de ahí se puede bajar .  

Importar un contenedor Docker en Python.



En los artículos anteriores sobre Docker se ha tocado el manejo de imagenes, ahora se explicará como importar un contenedor desde Python, este artículo se basa en el siguiente artículo en inglés.

Los artículos anteriores de Docker son:
  1. Instalar Docker en Debian Jessie
  2. Uso de Docker en Debian Jessie (parte 1)
  3. Uso de Docker en Debian Jessie (parte 2)
  4. Crear una imagen Docker a partir de un archivo Dockerfile
  5. Iniciando Django usando Docker
  6. Instalar Gitlab por medio de Docker
  7. Ejecutando microservicios con docker usando docker-compose
  8. Docker en Docker (DinD)
  9. Iniciando Django con docker usando docker-compose con postgresql como microservicio.

Se tiene el módulo Sidomo que permite manejar contenedores.

Para instalar sidomo se ejecuta el comando pip:

pip install -e git+https://github.com/deepgram/sidomo.git#egg=sidomo

Se baja la imagen Docker de Ubuntu:
docker pull ubuntu

El código de ejemplo del sitio de sidomo se encuentra en el siguiente enlace.


La modificación del código es el siguiente:

#!/usr/bin/env python
from sidomo import Container
def say_hello(to):
    """Just say it."""
    with Container(
        'ubuntu',
        stderr=False
    ) as c:
        for line in c.run(
            'echo Hola Mundo  %s' % to
        ):
            yield line
if __name__ == '__main__':
    for line in say_hello("desde un contenedor Docker"):
        print line
Al ejecutar el código se tiene:

python ejemplo.py 
Hola Mundo desde un contenedor Docker



AddThis