viernes, 3 de mayo de 2019

Wercker Intro

A mediados de abril del año 2017 (casi 2 años atrás), Oracle adquirió Wercker. Si bien ya existían productos para habilitar CI/CD en las organizaciones, Oracle vio una característica importante de Wercker: es una plataforma basada en Docker.

Por otro lado, en diciembre pasado (2018), Docker en conjunto con Microsoft anunciaron un nuevo estándar llamado CNAB (Cloud Native Application Bundle). Este estándar tiene como objetivo principal administrar en conjunto: infraestructura, aplicaciones y servicios cloud.

En qué atinó Oracle ese 2017: Docker se convertiría en un estándar tarde o temprano (aunque ellos quizá no lo sabían o, al menos, no estaban tan seguros). Mejor aún, lo que sucedió es que Docker ESCRIBIÓ un estándar. Y no sólo eso, sino que escribió un estándar para aplicaciones Cloud Native. La ventaja de Wercker sobre algunas otras plataformas que ofrecen CI/CD es que desde su concepción está basado en Docker.

Ahora bien: ¿qué es Wercker y cuáles son sus principales funciones o características?

  • Steps
  • Pipelines
  • Workflows

Steps

Son scripts bash o binarios que ayudan a automatizar tareas. Las tareas que automatizan se definen en un archivo llamado wercker.yaml asociado a la aplicación. Los steps los puede uno escribir a mano; o bien, pedirlos prestados a la comunidad. Recuerden que no estamos solos, siempre podemos echar mano de Internet. Estos pasos (los que pedimos prestados) se encuentran en un lugar que se llama Steps Registry.

Pipelines

Esta es la principal capacidad de Wercker. Es donde se define el flujo de las acciones (pasos) y el entorno de esas tareas. Es aquí donde se definen las tareas de build, test y deploy. Algo que presume mucho Wercker es que los pipelines pueden ejecutarse de manera concurrente, esto podría ayudar en el tiempo de ejecución del pipeline.

Workflow

Esta característica es la configuración del circuito. En un workflow podemos incluir uno o varios pipelines y configurarlos en serie o en paralelo (sí, como un circuito eléctrico). De tal suerte que de acuerdo a nuestro diseño de los pipelines (conjunto y configuraciones de steps), podríamos reutilizar distintos pipelines en distintos workflows. Esto nos permite diseñar configuraciones de pipelines (workflows) tan simples o complejos como necesitemos.

Otras funciones

Adicional a las anteriores, Wercker proporciona algunas otras funciones o capacidades. Por ejemplo, cuenta con integración con repositorios basados en Git (el de tu preferencia: GitHub, GitLab, Bitbucket, entre otros). Esta funcionalidad es básica para cualquier pipeline de CI/CD, pues es necesario obtener el código fuente de algún lado para ejecutar tareas de build, test o deploy.


martes, 27 de noviembre de 2018

MICROSERVICIOS CON HELIDON

Una alternativa tecnológica para escribir microservicios en Java es Helidon, un nuevo proyecto de Oracle. Veamos qué tal le va en ésta competencia.


Hechos


Cuenta con tres componentes:

  1. WebServer: un API HTTP con características reactivas, provistas por Netty.
  2. Config: un framework de configuración flexible que soporta múltiples fuentes y formatos.
  3. Security: herramientas para autenticación, autorización y propagación de contexto.
Se puede elegir entre dos modelos de programación:
  1. Helidon SE: estilo de programación funcional que usa los tres componentes mencionados anteriormente.
  2. Helidon MP: modelo declarativo que soporta las APIs de Microprofile
Cuenta también con soporte para Docker y Kubernetes, lo que lo hace atractivo para aplicaciones con arquitecturas basadas en microservicios.

Prerrequisitos

Al parecer los prerrequisitos son muy simples:
  1. Java 8 o superior
  2. Maven
Opcionalmente:
  1. Docker, si necesitamos desplegar en contenedores.
  2. Kubectl, si necesitamos desplegar en Kubernetes
  3. Kubernetes Cluster
Las versiones mínimas son las siguientes:
  1. Java 8 SE u Open JDK 8
  2. Maven 3.5
  3. Docker 18.02
  4. Kubectl 1.7.4
No se necesita nada adicional. Veamos si es tan simple como parece.

Máquina Virtual


Estoy usando una máquina virtual que me pasó mi compi @domix. Validaré los prerrequisitos:


Arquetipos

Como mencioné anteriormente, existen dos modelos de programación que podemos elegir: Helidon SE y Helidon MP. El primer paso es generar el proyecto usando los arquetipos de Maven para Helidon. El resultado será un servicio REST con la misma API, sin embargo, la implementación es distinta.

Helidon SE


Helidon MP


Proyectos

Lo anterior generará dos proyectos: uno de Helidon SE y otro de Helidon MP. Misma API REST, distinta forma de implementar.


Construcción de la aplicación

Para ambos casos (SE y MP), vamos a construir la aplicación utilizando Maven.


Lo anterior, va a compilar el código, ejecutar un set de pruebas y finalmente crear un JAR.

La diferencia entre SE y MP es el servidor que ejecuta la aplicación. En el caso de Microprofile, el tiempo de arranque es de 151 milisegundos. ¡Nada mal!


Finalmente, podemos observar los JAR generados de la aplicación. También se puede observar que el JAR de MP es ligeramente más grande que el de SE. Es el precio por tener un arranque mucho más rápido, aunque la diferencia en tamaño del mismo código no es significativa.

Ejecutar y Probar la Aplicación

Ahora que ya tenemos el paquete, vamos a ejecutarlo y probarlo. La ejecución es simple, como cualquier otro JAR ejecutable. Al ser un servicio REST el que expusimos en la aplicación, sólo tenemos que enviar peticiones HTTP adecuadas. El set de pruebas ejecutado es el siguiente:
  1. GET a /greet, RESPONSE: Hello World!
  2. GET a /greet/{nombre}, RESPONSE: Hello {nombre}!
  3. PUT a /greet/greeting/{saludo} (esto modificará el mensaje del saludo), RESPONSE: {saludo}
  4. GET a /greet/{nombre}, RESPONSE: Hola (nuevo saludo) {nombre}!

Helidon SE

Helidon MP

No es por presumir, pero ésta vez la aplicación tardó 136 milisegundos en iniciar. El servicio expuesto cumple con la misma interfaz que en el caso de SE, por lo que si ejecuto el mismo set de pruebas, el resultado debe ser el mismo.

Conclusiones

Pienso que al ser Helidon una colección de librerías para escribir microservicios en Java, muchos desarrolladores de la comunidad pueden tanto colaborar como hacer uso de ellas. Me parece que podría haber un buen futuro si se promueve el uso y colaboración en el desarrollo del proyecto.

Iniciar a escribir código es muy rápido (quizá no tanto como el Starter de SpringBoot, pero bastante decente), además de que el uso de Maven y los arquetipos hace que tengas un proyecto de código listo literalmente en minutos (versión inicial o cascarón).

La opción de Microprofile ha sido una gran decisión, pues ayuda en la controversia del uso de Java (y el tiempo de inicio) en arquitecturas orientadas a microservicios. En mi caso, la aplicación tarda en promedio 150 milisegundos en iniciar. Me parece un tiempo bastante decente para una aplicación de éste estilo. Faltaría probar al incluir más servicios y con mayor complejidad y dependencias.

Helidon SE

Si revisamos un poco el código, es bastante simple. Tenemos una clase principal de la aplicación, donde definiremos el inicio del servidor y el contexto inicial o base de la API REST:



Del lado de la implementación, tendríamos que sobreescribir el método update de la clase Service para definir las URIs y métodos HTTP a exponer, así como la referencia a los métodos que implementan la lógica de cada recurso:


Finalmente, escribimos la lógica de cada uno de los métodos de implementación de los recursos:

Helidon MP

Para el caso de Microprofile, tenemos una clase principal muy similar donde definimos el contexto base de la aplicación. Sin embargo, los métodos para iniciar la aplicación y la configuración del logging resultan mucho más simples:

El resto del código es el de una aplicación con JAX-RS usando Java EE:


Esto parece una buena decisión, pues quienes ya creaban aplicaciones con JAX-RS, lo van a poder seguir haciendo de la misma forma y aquí el que sirve es Microprofile.

Docker y Kubernetes

La decisión de soportar Docker y Kubernetes hace a Helidon una alternativa bastante interesante para aplicaciones Cloud Native pues, como dijo mi amigo @RuGI, Docker no debe tardar en convertirse en un estándar en contenedores. 

martes, 14 de agosto de 2018

FN Project - Instalación y primera función

Intro

Fn es una plataforma cloud FaaS (Funtions-as-a-Service) de código abierto. Está basada en eventos y puede correr en cualquier nube (cloud agnostic serverless platform).

Entre otras, algunas características principales de éste proyecto son:
  • Código abierto
  • Docker native
  • Múltiples lenguajes de programación
  • Agnóstica a la nube (corre en cualquier nube)
  • De fácil uso (principalmente para desarrolladores y operadores)
  • Está escrita en Go


Instalación

Los pre-requisitos son simples:
  1. Tener instalado y corriendo Docker 17.10.0-ce o superior
  2. Tener una cuenta de Docker Hub
  3. Hacer login en la cuenta de Docker Hub
Instalar la línea de comandos de Fn (CLI)

Esto no es requerido, pero a nadie le cae mal una ayuda. Nos va a facilitar algunas cosas.

Estoy usando Linux, hay maneras de hacerlo en Windows y MacOS. Aquí vamos a mostrar cómo se hace en Linux.

Debemos descargar un shell y ejecutarlo. En caso de estar usando root, todo será transparente. En caso de estar utilizando algún otro usuario, nos va a pedir el password para invocar sudo.

curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

Al finalizar la descarga e instalación, veremos lo siguiente en la línea de comandos. En este punto la herramienta de CLI estará instalada:


Podemos verificar que la instalación de CLI fue correcta ejecutando el comando: fn help


Ejecución del Fn Server

El siguiente paso es descargar el binario de Fn. Aquí van a encontrar las versiones disponibles, deberán descargar el que corresponde a su sistema operativo (en mi caso, Linux):


Una vez descargados los binarios, podemos ejecutar el comando para iniciar el fn server: fn start

Como era de esperarse, mi versión de docker era muy vieja. Entonces el primer intento no funcionó.


Pero no se agüiten. Sólo es necesario remover el docker-engine actual e instalar la versión más nueva y chévere de docker-ce (hay que agregar el repositorio correspondiente para poder instalar docker-ce).

Desinstalar docker-engine

sudo yum remove docker


Agregar repositorio de docker-ce e instalar la última versión

sudo yum -y install yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum -y install docker-ce


Verificar la instalación de docker-ce

docker version


Podemos ver un mensaje que nos indica que el Docker daemon no está iniciado. Como acabamos de instalar docker-ce, debemos iniciar manualmente el demonio y verificar nuevamente. Para poder iniciar el demonio con systemctl, nos va a solicitar el password de sudo:

systemctl start docker
docker version


Segundo intento, levantar el fn server

fn start


Primera función

fn init

Para escribir nuestra primera función, vamos a usar la herramienta CLI que instalamos al inicio. Esto va a permitir crear la primera versión de manera muy simple. Lo unico que debemos hacer es escribir: fn init --runtime go hello

Lo anterior, automáticamente va a generar una carpeta llamada hello y debajo de ella cuatro archivos correspondientes al código de nuestra función:


func.go

El archivo func.go contiene el código de la función. Es un simple hello world. Básicamente la función recibe un parámetro (name). En caso de que el parámetro esté vacío, devuelve "Hello World". En caso de que el parámetro contenga un valor, devuelve un saludo personalizado "Hello Leo".


func.yaml

El archivo func.yaml es llamado func file y es usado para la creación de las funciones de fn project. Lo que definimos en el archivo es: el nombre de la función, la versión de la función, el lenguaje de programación en tiempo de ejecución y el formato de los mensajes.


Gopkg.toml

El archivo Gopkg.toml es un archivo de configuración donde se definen las dependencias de la función.


test.json

El archivo test.json es un archivo utilizado para realizar pruebas de ejecución de la funcion, define entradas y salidas de la función. Esto nos ayudará a saber si la función está operando correctamente o no.


Ejecutar la función localmente

Una vez que está listo el código, vamos a ejecutarlo y a desplegarlo al Fn server local. Para el despliegue vamos a utilizar nuestro usuario de Docker Hub que comentamos al inicio, en los pre-requisitos del post. Vamos a hacer un export a la variable de ambiente FN_REGISTRY, con el usuario de Docker Hub. Una vez hecho esto, vamos a ejecutar la función localmente: fn run

Desplegar la función al Fn server local

Para desplegar la función a nuestro Fn server local, vamos a utilizar el comando: fn deploy --app myapp --local



Probar la función

Para poder probar la función en nuestro Fn server local, vamos a ejecutar alguna de las siguientes opciones:

  1. Probar en el navegador: http://localhost:8080/r/myapp/hello
  2. Probar usando curl: curl http://localhost:8080/r/myapp/hello
  3. Probar usando CLI: fn call myapp /hello
Navegador (usando Firefox):


CURL:


CLI:


HTTPie

Adicionalmente hice un par de pruebas usando HTTPie. Es una herramienta en modo línea de comandos que nos sirve para enviar requests a un endpoint usando los distintos métodos de HTTP. Esto me va a permitir ejecutar tanto un GET como un POST en el mismo endpoint y poder pasar el nombre a la función sin tener que armar a mano el JSON del payload.

HTTPie (GET):


HTTPie (POST):


miércoles, 7 de marzo de 2018

Automatización de pruebas de OSB usando SOAP UI.

En esta entrada voy a mostrar cómo es posible automatizar pruebas de servicios desplegados en OSB, haciendo uso de SOAP UI.

Los pasos a seguir son simples:

1. Construir un servicio y exponerlo en OSB.
2. Crear un proyecto de SOAP UI para probar el servicio.
3. Hacer uso de Maven para probar y desplegar el proyecto.

Imaginemos el siguiente escenario: tenemos un servicio en un entorno de desarrollo (desplegado) y lo queremos promover a un ambiente de pruebas. Previo a realizar esto, debemos asegurarnos que nuestro servicio funciona de manera adecuada y que hace lo que debe hacer.

Para ese propósito ocupamos SOAP UI, generamos algunos casos de prueba y los colocamos en una Test Suite y probamos. Una vez que aseguramos que todos los casos de prueba se ejecutan correctamente, podemos pasar a la automatización de esas pruebas.

En mi caso, creé un servicio simple que devuelve un saludo (cómo crear el servicio, esquemas, pipeline, etc., no es el objetivo de esta entrada pero pueden crear uno muy simple). Posteriormente, creé el proyecto en SOAP UI, una Test Suite (llamada Pruebas) y un Test Case (saludar TestCase). Agregué un par de pasos de ejecución para las pruebas y algunos assertions para cada paso. Ejecuté el test case y estos fueron mis resultados:


Al ejecutar cada uno de los pasos, mis resultados fueron los siguientes:



Como vemos, el servicio cumple con los casos de prueba diseñados. Esto podría significar que está listo para ser promovido a un ambiente de pruebas. Para asegurarnos que el código que estamos desplegando esté bien probado antes de ser promovido, y que esto se haga de forma automática, podemos hacer uso de un plugin de Maven. Esto es tan simple como agregar lo siguiente al POM del proyecto:

  <pluginRepositories>
    <pluginRepository>
      <id>smartbear-sweden-plugin-repository</id>
      <url>http://www.soapui.org/repository/maven2/</url>
    </pluginRepository>
  </pluginRepositories>
  <build>
    <plugins>
      <plugin>
        <groupId>com.smartbear.soapui</groupId>
        <artifactId>soapui-maven-plugin</artifactId>
        <version>4.6.1</version>
        <executions>
          <execution>
            <id>QClearanceTest</id>
            <goals>
              <goal>test</goal>
            </goals>
            <phase>test</phase>
          </execution>
        </executions>
        <configuration>
          <projectFile>${basedir}/Test/test-soapui-project.xml</projectFile>
          <testSuite>Pruebas</testSuite>
          <testCase>saludar TestCase</testCase>
          <endpoint>http://localhost:7001/v1/SOAPUI/TestSuite.svc</endpoint>
          <outputFolder>${basedir}/Reporte</outputFolder>
          <junitReport>true</junitReport>
          <printReport>true</printReport>
          <settingsFile>${basedir}/Test/soapui-settings.xml</settingsFile>
        </configuration>
      </plugin>
    </plugins>
  </build>

Lo que marco en naranja, es básicamente lo que tendría que cambiar de acuerdo a cómo hayan hecho la implementación del servicio. En mi caso:

- El endpoint de mi servicio está en localhost, por el puerto 7001
- La Test Suite de SOAP UI, la llamé Pruebas
- El Test Case de SOAP UI, lo llamé saludar TestCase
- En caso de haber un error en las pruebas, quiero que se genere un reporte debajo de la carpeta ${basedir}/Reporte (donde tengo mi proyecto de OSB, debajo de una carpeta llamada Reporte).
- Tanto el proyecto de SOAP UI, como el archivo de instalación del producto, los puse debajo de la carpeta Test.

Así quedó la estructura de mi proyecto de OSB:

- Reporte, es la carpeta donde el plugin va a almacenar el reporte de ejecución de las pruebas
- Test, es la carpeta donde coloqué el XML del proyecto de SOAP UI (test-soapui-project.xml) y el XML de la instalación del producto (soapui-settings.xml)

Hay algunas consideraciones respecto al proyecto de SOAP UI para que pueda funcionar bien el plugin:

- SOAP UI por default coloca "\r" al finalizar una línea en los payloads de prueba. Esto se ve en el XML del proyecto de SOAP UI. Simplemente hay que eliminar las "\r".
- SOAP UI por default coloca "No Authorization" cuando no tenemos algún tipo de autorización. Esto se valida en un enumeration de un esquema, y "No Authorization" no es parte de ese enumeration. Así es que hay que eliminarlo (o comentarlo en el código).

Entonces, el proyecto de SOAP UI que adjuntamos a nuestro proyecto de OSB, se debe corregir de la siguiente forma (izquierda: incorrecto, derecha: correcto):




Una vez corregido el proyecto de SOAP UI, lo podemos probar localmente ejecutando mvn test:



Lo más importante de haber logrado automatizar las pruebas, es que esto se incluya antes del despliegue. Para esto, debemos haber poblado nuestro repositorio local con los artefactos de Oracle, para así poder ejecutar: mvn pre-integration-test. La documentación de cómo hacer esto, la pueden encontrar aquí:


Lo anterior, realizará las pruebas previo al despliegue del servicio (en el ambiente indicado). Entonces, al ejecutar mvn pre-integration-test, tendremos lo siguiente (además del servicio probado y desplegado en el ambiente destino):


Podría concluir que el uso del plugin de SOAP UI es muy útil para validar que nuestros servicios se comporten de la manera en que se espera, previo al despliegue a un ambiente de calidad o productivo. En conjunto con los artefactos de Oracle, esto puede ser un buen inicio para automatizar las pruebas y despliegues, generando así los primeros pasos de un entorno de CI/CD.

Además nos obligamos a diseñar y ejecutar casos de prueba. Es muy importante entender que los defectos deben ser encontrados y corregidos (en su mayoría) por el desarrollador, no por el equipo encargado de realizar QA. Si diseñamos y ejecutamos esas pruebas previo al despliegue, minimizamos la cantidad de defectos que pudieran ser encontrados después. Entre más robusto sea el diseño de esos casos de prueba, entregaremos un producto de mejor calidad y con menor número de defectos. Hagamos ésta una práctica del equipo de desarrollo.

martes, 19 de diciembre de 2017

Primer Chatbot - Dialogflow (Google Platform)

Al finalizar la entrada anterior del blog, comenté que iba a hacer un ejemplo usando Dialogflow (antes API.AI). Dialogflow es una plataforma Cloud de Google para desarrollar chatbots.

Me ha sorprendido la facilidad de uso de la plataforma, es bastante intuitiva y simple de usar. Previamente hay que diseñar y establecer el flujo de la conversación que deseamos implementar con el chatbot. Y una vez entendidos los conceptos que describimos en la introducción de esta serie de posts, podemos saltar a construir nuestro primer ejercicio.

La consola.


Para poder acceder al servicio, primero debemos darnos de alta. Esto se puede realizar teniendo una cuenta de correo de Google. La consola es limpia, simple y se ve de la siguiente forma una vez que hacemos login a la plataforma.


El agente.


Un agente contiene intents, entities y responses para poder interactuar con un usuario. Hablaremos con los nombres de los conceptos en inglés, que es como se encuentran en la plataforma.

Para poder crear un nuevo agente, basta con seleccionar el siguiente botón en la consola de la plataforma.

Posteriormente, veremos una pantalla que nos permitirá realizar las primeras configuraciones (programación) de nuestro agente.


Aquí basta con colocar un nombre al agente y el idioma que vamos a utilizar. La plataforma ofrece ya varias opciones: alemán, inglés, francés, español, italiano, japonés, coreano, holandés, portugués, ruso, ucraniano y varios tipos de chino. Además permite definir la zona horaria. Una vez que realizamos las primeras configuraciones, podemos presionar en el botón Create que se encuentra en la parte superior derecha.


Los intents.


Lo primero que nos ofrece la plataforma, es la configuración de los intents. Por default, existen dos intents previamente creados en nuestro agente, estos los mantendremos como originalmente configurados. El primero de ellos es para saludar (Default Welcome Intent) y el segundo es utilizado para dar una respuesta en caso de no comprender la solicitud del usuario (Default Fallback Intent).


Mi primer intent, decidí hacerlo para hablar de fútbol. El fútbol es el tema preferido de muchos, y mucho más cuando se acerca la fecha del mundial de Rusia 2018. Además de que acabamos de tener campeón regio del fútbol mexicano. Así que configuré el siguiente intent.


En el ejemplo anterior, al agregar las posibilidades de interacción con el usuario (User says), podemos observar algunas palabras resaltadas en colores: México, Rusia y 2018. Esto significa que son anotadas como parámetros que son asignados a algunas entidades del sistema como fecha y ciudad. Estos parámetros nos ayudarán a entender otras ciudades y fechas proporcionadas por el usuario y no sólo las que configuramos en el intent.

A continuación presionamos el botón Save que se encuentra arriba a la derecha para poder probar por primera vez nuestro agente. Veamos qué sucede.

Los responses.


Debido a que no tenemos configuradas las respuestas a nuestro intent (al menos no para el del fútbol), el chatbot no devolverá respuesta alguna. Sin embargo, podrá reconocer los parámetros que se colocan en el mensaje de entrada del usuario. Por ejemplo, una de las frases que colocamos en la sección User say del intent fue: "Equipo más popular en México". El intent automáticamente reconocerá México o Brasil o Rusia o cualquier otro país como un parámetro que forma parte de las entidades del sistema (sys.geo-city) y devolverá un valor "Not available" como respuesta default. Esto está bien, pues no hemos configurado respuesta alguna todavía. También notaremos que el intent ejecutado es el que configuramos "Futbol Intent"


En caso de que coloquemos una frase sin sentido, el intent que se ejecutará es el "Default Fallback Intent" y devolverá alguna de las respuestas configuradas. Intentemos eso.

Finalmente, vamos a configurar algunos responses para nuestro intent. En mi caso coloqué los siguientes. Notemos que en las respuestas asocié los parámetros recibidos en la solicitud del usuario. Entonces, el chatbot tiene manera de asociar esos parámetros de entrada, a la respuesta de salida que va a elegir de la lista.


Por lo tanto, si le pregunto cuál es el campeón del mundo actual, no podrá nunca responderme con: "El campeón del siguiente mundial en Rusia 2018 será Perú", puesto que en la entrada no estoy usando entidades del sistema como parámetros, por lo tanto el chatbot no elegirá una respuesta que sí usa esa información en alguna de las salidas posibles.

Las primeras pruebas.


Estas son las respuestas que obtenemos de este ejercicio:





Siguientes pasos.

En la siguiente entrada del blog, vamos a hacer al chatbot un poco más inteligente. Se me ocurre que puedo publicar un API que reciba algunos parámetros y devuelva estadísticas del fútbol que tanto nos gusta. Así, de acuerdo a las entradas recibidas podremos obtener las estadísticas de un API y devolver una respuesta más coherente al usuario.