25 jun. 2017

Desarrollar un API con GraphQL en Flask

Continuando con los artículos sobre Flask, donde el último artículo fue de como crear un API Restful con Flask y MongoDB.

En este artículo se toca el uso de GraphQL para crear un API. GraphQL es un lenguaje de consulta de datos desarrollado por Facebook, es una alternativa a Rest (más información en wikipedia).

La librería para Flask de GraphQL lo pueden ver en el siguiente enlace. El artículo explicará el ejemplo que aparece en la página oficial de graphQL para Flask.

Instalación:
#pip3 install flask graphene flask-graphql


Script servidor (server.py):


#!/usr/bin/env python3

#Se importa flask, graphene y graphql.

from flask import Flask

from graphene import ObjectType, String, Schema

from flask_graphql import GraphQLView



#Se crea la clase Query que hereda de graphene ObjectType.

class Query(ObjectType):

    #Se define la descripcion

    hello = String(description='Hello')

    #Se define la funcion resolve_hello, se le pasa args, context e info.

    def resolve_hello(self, args, context, info):

        return 'World'



#Se define la funcion de la vista.

#que se le pasa el esquema con la clase Query.

view_func = GraphQLView.as_view('graphql', schema=Schema(query=Query))



#Se crea la app como instancia de la clase Flask.

app = Flask(__name__)

#Se define el url donde se le pasa la funcion de la vista

app.add_url_rule('/', view_func=view_func)



if __name__ == '__main__':

    #Se ejecuta flask.

    app.run()



Al ejecutar el script:


Se consulta usando curl:
curl -H 'Content-type: application/graphql' -d '{hello}' http://localhost:5000/

Y este devuelve:

{"data":{"hello":"World"}}




Desde un script en python:



Instalación de librerías necesarias:

#pip3 install gql requests



El script cliente.py :



#!/usr/bin/env python3



#Se importa json

import json

#se importa ggl

from gql import gql, Client

from gql.transport.requests import RequestsHTTPTransport



#Se define el transport, se conecta el cliente.

transport = RequestsHTTPTransport('http://localhost:5000/')

client = Client(transport=transport)

#Se realiza una consulta buscando la  variable hello

response = client.execute(gql('{hello}'))



#muestra en pantalla la respuesta como un json.

print(json.dumps(response))



Se ejecuta el script:

python3 cliente.py 
{"hello": "World"}

En un artículo en genbetadev comparan API Restful con GraphQL y por que es necesario dejar de usar API Restful.
En futuros artículos se ampliará el uso de GraphQL.

24 jun. 2017

Base de datos InfluxDB en Debian Stretch

InfluxDB es una base de datos opensource de series de tiempo, para manejo de eventos,monitoreo, métricas, Internet de las cosas y Analítica en tiempo real. Desarrollada por InfluxData en Lenguaje Go. Pueden ver más información en wikipedia.

Para instalar en Debian simplemente se usa apt-get:

# apt-cache search influxdb 
golang-github-influxdb-enterprise-client-dev - Golang client for speaking to the InfluxDB Enterprise application
golang-github-influxdb-usage-client-dev - library for speaking to the InfluxDB Anonymous Usage Reporting API
golang-gopkg-alexcesaro-statsd.v1-dev - simple and efficient Golang StatsD client
golang-github-influxdb-influxdb-dev - Scalable datastore for metrics, events, and real-time analytics. Dev package
influxdb - Scalable datastore for metrics, events, and real-time analytics
influxdb-client - command line interface for InfluxDB
influxdb-dev - Transitional package for golang-github-influxdb-influxdb-dev
ruby-influxdb - library for InfluxDB


Para instalar:

# apt-get install influxdb influxdb-client

Para probar que está en funcionamiento:

# influx
Visit https://enterprise.influxdata.com to register for updates, InfluxDB server management, and monitoring.
Connected to http://localhost:8086 version 1.0.2
InfluxDB shell version: 1.0.2




Para crear una base de datos llamada mydb:

> create database mydb

Listar las bases de datos:

> show databases
name: databases
---------------
name
_internal
mydb



Insertar datos y consultarlos en la base de datos mydb:

> use mydb
Using database mydb
> INSERT cpu,host=ServerA,region=us_west value=0.64
> SELECT host, region, value FROM cpu
name: cpu
---------
time                 host         region value
1498340879346347895 ServerA us_west 0.64

Por lo que se ve, la clave primaria de los datos siempre es el tiempo. 

Ahora una pequeña prueba con Python.

Para instalar la librería en Python:
# pip3 install influxdb



Se tiene el siguiente script:


#!/usr/bin/env python3
#Se importa influxdb
from influxdb import InfluxDBClient
#Se define un json con los datos a insertar
json_body = [
    {
        "measurement": "cpu_load_short",
        "tags": {
            "host": "server01",
            "region": "us-west"
        },
        "time": "2009-11-10T23:00:00Z",
        "fields": {
            "value": 0.64
        }
    },
    {
        "measurement": "cpu_load_short",
        "tags": {
            "host": "server02",
            "region": "us-west"
        },
        "time": "2009-12-10T23:00:00Z",
        "fields": {
            "value": 0.65
        }
    }
]
#Se conecta a la base de datos
client = InfluxDBClient('localhost', 8086, 'root', 'root', 'mydb')
#Se crea la base de datos mydb
client.create_database('mydb')
#Se inserta los datos
client.write_points(json_body)
#Se consulta y se muestra en pantalla
result = client.query('select value from cpu_load_short;')
print("Result: {0}".format(result))

Al ejecutar el script, este devuelve lo siguiente:

./prueba-influxdb.py 
Result: ResultSet({'('cpu_load_short', None)': [{'value': 0.64, 'time': '2009-11-10T23:00:00Z'}, {'value': 0.65, 'time': '2009-12-10T23:00:00Z'}]})


O desde el cliente de influxdb:

> use mydb
Using database mydb
> select value from cpu_load_short;
name: cpu_load_short
--------------------
time value
1257894000000000000 0.64
1260486000000000000 0.65

Como se muestra, la clave que maneja las consultas es el tiempo.

Para más información se tiene los siguientes enlaces:



Obtener datos de eventos sismológicos de Funvisis con Python3 (segunda versión)

El primer artículo sobre obtener los datos sismológicos de Funvisis con Python, se usó la librería python-mechanize, en este caso se usará la librería request y Python 3.* .



El código se muestra a continuación:


#!/usr/bin/env python3





#Se importa beautifulSoup

from bs4 import BeautifulSoup

#Se importa la fecha

from datetime import datetime

import requests

import sys

import json



class Sismo(object):

    def __init__(self,url="http://www.funvisis.gob.ve/",home="index.php",referer='http://www.cantv.com.ve'):

        headers = {'User-agent': 'Mozilla/5.0',\

            'SSL_VERIFYHOST': 'False',\

            'FRESH_CONNECT':'True',\

            'RETURNTRANSFER':'True',\

            'SSL_VERIFYPEER': 'False',\

            'Referer': referer

            }

        self.__url = url

        self.__home = home

        self.__urlhome = self.__url + self.__home

        self.__session = requests.Session()

        self.__session.headers.update(headers)



    def GetData(self):

        #Se  obtiene la pagina por medio de session.

        try:

            self.__r = self.__session.get(self.__urlhome)

            self.__page = self.__r.content

        except (requests.exceptions.SSLError):

            print("SSL Error")

            sys.exit(0)

        except (requests.exceptions.ConnectionError):

            print("Connection Error")

            sys.exit(0)

        #Se le pasa la pagina a beautifulsoup usando lxml de parser.

        self.__soup = BeautifulSoup(self.__page,"lxml")

        #Se crea el diccionario que almacena los datos

        self.__sismo = {}



        #SE obtiene el primer  div que tengan class module

        for row in self.__soup('div', {'class': 'module'})[0]:

            #Se obtiene el tag a para luego obtener el href y tener el url

            #del gif del sitio de funvisis que tiene la imagen del sitio donde

            #fue el sismo.

            trs = row.find('a')

            if trs == -1:

                continue

            self.__sismo['urlref'] = self.__url  + trs.get('href',None)



            trs = row.find('tr')

            if trs == -1:

                continue

            #Obtiene los datos del sismo del sitio de funvisis

            datos = trs.find('td').getText().split(' ')

            self.__sismo['fecha'] = datos[0].split('\n\t')[0].split('\xa0')[1]

            self.__sismo['hora'] = datos[0].split('\n\t')[2].split(" ")[-2]

            self.__sismo['magnitud'] = datos[0].split('\n\t')[4].split(" ")[-1]

            mag = datos[0].split('\n\t')[6].split(" ")[-1].split('\xa0')

            self.__sismo['profundidad'] = mag[0] + " "+ mag[1]

            lat = datos[0].split('\n\t')[8].split(" ")

            self.__sismo["latitud"] = lat[-2] + " " + lat[-1]

            lon =  datos[0].split('\n\t')[10].split(" ")

            self.__sismo['longitud'] = lon[-2] + " "+ lon[-1]

            self.__sismo['epicentro'] = datos[0].split('\n\t')[11].split(":")[1].split('\xa0')[-1]

        return self.__sismo







  



  def ToJSON(self):

        self.__sismojson = json.dumps(self.GetData())

        return self.__sismojson





if __name__ == '__main__':
sismo = Sismo(
)
 
  



p
r
int
 
(
sismo.ToJSON())

Al ejecutar el script se tiene de resultado:

{"epicentro": "30 Km al sur de Guiria", "hora": "07:51", "latitud": "10.39 \u00baN", "longitud": "-62.32 \u00baO", "fecha": "24/06/2017", "magnitud": "2.8", "urlref": "http://www.funvisis.gob.ve/images/reportes/2017/06/reporte_7489.gif", "profundidad": "9.1 km"}


El código se puede ver en el repositorio en gitlab.

10 jun. 2017

Fabric como un ssh con esteroides en Debian Stretch

Fabric es una librería y herramienta de línea de comandos que genera un flujo de tareas para la automatización de despliegues y tareas administrativas de manera remota.


Este artículo se basa en un vídeo de youtube de una introducción a Fabric.


Se tiene 3 equipos:

  • 192.168.1.3: Equipo con Debian Stretch y donde se tiene fabric instalado.
  • 192.168.1.2: Equipo con Debian Stretch.
  • 192.168.1.6: Equipo con Debian Jessie.


Sólo se necesita un equipo con Fabric, se usa Debian Stretch por que en esta versión de Debian no es tan complicado de instalar Fabric, en Debian Jessie me ha dado algo de problemas, se logra instalar pero da errores en la ejecución (por lo que he investigado el problema es la librería paramiko).

Instalación de Fabric:
Con pip:
#pip install fabric


Ahora se crea un archivo fabfile.py co el siguiente contenido:


#!/usr/bin/env python

#de la api de fabric de importa run, sudo, task, get y put

from fabric.api import run,sudo,task,get, put



#Se define la tareta cmdrun que ejectua el argumento

@task

def cmdrun(arg):

    run(arg)



#Se define la tarea sudorun que ejecuta el argumento vía sudo

@task

def sudorun(arg):

    sudo(arg)



#Se define la tarea download que se le pasa un argumento que se descarga en /tmp/

@task

def download(arg):

    get(remote_path=arg,local_path="/tmp/",use_sudo=True)



#Se define la tarea upload que se le pasa dos argumentos

#local_path y remote_path.

@task

def upload(arg1,arg2):

    put(local_path=arg1,remote_path=arg2,use_sudo=True)



#Se define la tarea host_type que ejecuta uname.

@task

def host_type():

        run('uname -s')





Para ejecutar las tareaas se usa el comando fab (se define una variable de entorno llamada clave la cual maneja la clave del usuario):

Ejecución de ps en dos equipos en paralelo:
fab -H 192.168.1.2,192.168.1.6 -p $clave -P cmdrum:"ps -ef|wc -l"


Devuelve la ejecución del ps y la cantidad de líneas que resulta en cada equipo.

Se averigua el tipo de host de cada equipo remoto con host_type:
fab -H 192.168.1.2,192.168.1.6 -p $clave   host_type

Acá se muestra de manera secuencial la ejecución de los comandos en los equipos, par aque sea de manera paralela se usa la opción -P.
fab -H 192.168.1.2,192.168.1.6 -p $clave  -P host_type



Ya la ejecución no se hace de manera secuencial en cada equipo.


Se ejecuta fdisk por medio de sudo:
fab -H 192.168.1.2,192.168.1.6 -p $clave -P sudo:"fdisk -l| grep sda"



El comando devuelve las particiones sda que tiene cada equipo.


Se sube un arhivo sources.list al equipo 192.168.1.2, por medio de upload y se pasa como argumento el archivo local y la ruta remota:
fab -h 192.168.1.2 -p $clave upload:"sources.list","/tmp/"


La figura muestra que la subida del archivo se realizó sin problemas, ahora se revisa en el directorio /tmp/:
La figura muestra que el archivo sources.list se encuentra en /tmp/



Se baja el  archivo prueba.txt del equipo 192.168.1.2, por medio de download, pasando la ruta remota del archivo, este archivo se descarga por defecto en /tmp/:

fab -H 192.168.1.2 -p $clave upload:"sources.list","/tmp/"


En este caso se descargo el archivo /home/ernesto/prueba.txt a /tmp/, luego se listo localmente el archivo para verificar que se encuentra el dicho directorio.


Un tutorial más completo sobre Fabric lo pueden encontrar en su sitio.

Otros vídeos de sobre fabric: