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.