Automatización con el marco Mule – Algorand

Mule es un marco de automatización generalizado para organizar la ejecución de la automatización definida en un formato declarativo yaml. Para algún contexto sobre por qué una herramienta como esta es útil, exploraremos el problema que está tratando de resolver.

El problema

Hoy en día hay cientos, o incluso miles, de herramientas en el mercado que son muy buenas para ejecutar acciones muy específicas que son útiles como parte del proceso CICD de una aplicación. El problema es que para usar estas herramientas, los ingenieros necesitan escribir scripts que ejecuten las funciones que necesitan, mientras que tienen especial cuidado de ejecutarlos en el orden correcto.

En la mayoría de los casos, esto conduce a scripts frágiles que están estrechamente acoplados a la aplicación en la que el desarrollador está trabajando. En Algorand, trabajamos en muchas pilas diferentes para garantizar que los desarrolladores puedan consumir todas las excelentes funciones que ofrecemos en nuestra plataforma. Por lo tanto, los scripts estrechamente acoplados no funcionarán para nosotros a escala.

Para resolver este problema, necesitábamos una herramienta que pudiera cumplir las siguientes condiciones:

La automatización se desacopla de los repositorios de proyectos. La automatización se puede consumir de una manera conveniente. La automatización se ejecuta de manera consistente tanto por los usuarios como por nuestro proceso CICD.

Existen algunas tecnologías de tuberías que casi cumplen con estas tres condiciones. El problema que tenemos con el uso de estas opciones es que no deseamos casarnos con ninguna tecnología de canalización, y también hay muchas cosas que nos gustaría automatizar que no necesitan ser parte de una canalización de aplicaciones. Por lo tanto, decidimos que estas opciones no eran lo suficientemente convenientes para nosotros.

Existen algunas herramientas en el mercado que cumplen con dos de las tres condiciones, pero la mayoría de ellas requieren scripts de punto de entrada en los repositorios de la aplicación, que falla la primera condición, o aprender una nueva sintaxis que no es simple o lo suficientemente liviana, que falla la tercera condición. Algunas combinaciones de estas herramientas podrían cumplir con las tres condiciones, pero sentimos que sus conjuntos de características serían demasiado diversos para el caso de uso simple que estábamos buscando.

Después de considerar estas opciones, decidimos explorar la construcción de nuestra propia solución a este problema.

Nuestra solución

Nuestra solución se llama Mula. Mule es un marco que generaliza el concepto de una unidad de automatización y le permite organizar su ejecución a través de un formato intuitivo y declarativo yaml. A continuación se muestra una explicación de cómo esta abstracción proporcionada por Mule cumple las condiciones establecidas:

La automatización se desacopla de los repositorios de proyectos.

Permite a los usuarios definir tareas automatizadas como scripts de python en una ubicación centralizada sin necesidad de scripts en los repositorios de aplicaciones.

La automatización se puede consumir de manera conveniente

Proporciona un lenguaje yaml simple e intuitivo para declarar configuraciones para tareas automatizadas y su orden de ejecución.

La automatización es ejecutada constantemente por los usuarios y nuestro proceso CICD

Proporciona un cli que puede consumir cualquier archivo mule yaml válido y ejecutar las tareas automatizadas de la misma manera en todas partes

Esta abstracción nos ha ayudado a comenzar a organizar nuestro proceso de CICD y nos ha dado la confianza de que podemos realizar el esfuerzo que lleva mucho tiempo de automatizar una tarea exactamente una vez para que podamos concentrarnos más tiempo en construir la red Algorand.

Antes de entrar en cómo usar mule para ejecutar la automatización, los siguientes son los conceptos clave del marco Mule.

Tareas

Una tarea es una unidad individual de automatización. Puede realizar una tarea para cualquier actividad que desee automatizar. Para obtener una lista de las tareas disponibles actualmente, consulte nuestra documentación de tareas. Los detalles sobre cómo escribir y usar tareas personalizadas estarán disponibles en las próximas semanas.

Trabajos

Un trabajo es una serie de tareas ejecutables, y una tarea en sí misma. Cuando proporciona un trabajo con una lista de tareas, el trabajo se encarga de evaluar la cadena de dependencias de las tareas que desea ejecutar y garantiza que todas las tareas requeridas por el trabajo y sus dependencias se ejecuten una vez en el orden en que se necesitan.

En esta sección proporcionaremos una serie de ejemplos para ayudarlo a acostumbrarse a la sintaxis utilizada en mule.yaml.

Si desea seguir esta guía, instale python 3.7+ y ejecute el siguiente comando para instalar el cli de mula.

pip install mulecli

Hola mule.yaml

Tareas:
– tarea: eco
mensaje: Mensaje para la consolajobs:
trabajo-a:
Tareas:
– Eco

Aquí tenemos un archivo de configuración de mula que enumera una tarea y un trabajo.

El campo de tareas es donde documenta las configuraciones de tareas que necesitará para ejecutar sus trabajos. Toma una lista de mapas (dictos en python) que se utilizan para inicializar sus tareas. Cada configuración de tarea debe tener un campo de tarea establecido. Mule lo usa para encontrar la tarea que desea inicializar. Cualquier otro campo es una configuración para su tarea. En este ejemplo tenemos una tarea llamada Echo, que simplemente imprime "Mensaje para la consola".

Luego tienes tu campo de trabajo. Aquí es donde define los trabajos y les proporciona una lista de tareas que desea ejecutar cuando se invoca el trabajo. La lista en el campo de tareas del trabajo contiene los identificadores de las tareas predefinidas, que en este caso es solo la definición de la tarea.

Cuando se invoca el trabajo-a, vemos la siguiente respuesta:

$ mule -f ruta / a / mule.yaml job-a
Mensaje para la consola

¡Y ahí tenemos nuestro primer trabajo de mula! Ahora veremos un ejemplo más interesante.

Dependencias de tareas

Tareas:
– tarea: eco
nombra un
mensaje: Mensaje para la consola
– tarea: eco
nombre: B
mensaje: otro mensaje para la consola
dependencias: Echo.Ajobs:
trabajo-b:
Tareas:
– Eco.B

Ahora tenemos dos tareas que estamos definiendo. La primera es una tarea Echo que imprime "Mensaje para la consola" y la segunda es una tarea Echo que imprime "Otro mensaje para la consola". Como estamos usando dos tareas que usan la misma definición de tarea, debemos proporcionar un campo de nombre a cada una que las diferencie. Cuando se introduce un campo de nombre en una tarea, su id se convierte en task_definition.name.

Una cosa más interesante aquí es el campo de dependencias en Echo.B. Este campo se usa para declarar que una tarea depende de otra tarea. De esta manera, cuando la tarea se ejecuta dentro de un trabajo, también se ejecutará cualquier otra tarea de la que dependa. Este campo puede ser una cadena delimitada por espacios o una lista de cadenas yaml. Tenga en cuenta el orden en que organiza estas dependencias, ya que las dependencias se ejecutarán en el orden en que las introduzca aquí.

Cuando se invoca el trabajo-b, vemos la siguiente respuesta:

$ mule -f ruta / a / mule.yaml job-b
Mensaje para la consola
Otro mensaje para la consola

Una cosa más a tener en cuenta es que este archivo es lógicamente equivalente al siguiente mule.yaml.

Tareas:
– tarea: eco
nombra un
mensaje: Mensaje para la consola
– tarea: eco
nombre: B
mensaje: otro mensaje para la consola
dependencias: Echo.Ajobs:
trabajo-b:
Tareas:
– Echo.A
– Eco.B

Independientemente de la disposición de las tareas, Mule evaluará la cadena de tareas dependientes que deben ejecutarse de modo que las tareas se ejecuten una vez en el orden en que se necesitan.

A continuación, veremos cómo puede parametrizar sus tareas.

Configuraciones de trabajo

Las configuraciones de trabajo son una forma de establecer campos en su mule.yaml que sobrescribirán los campos establecidos en sus configuraciones de tareas. De esta manera, puede definir tareas que pueden funcionar de manera diferente en diferentes trabajos.

Tareas:
– tarea: eco
nombra un
mensaje: Mensaje para la consolajobs:
trabajo-a:
configs:
mensaje: otro mensaje para la consola
Tareas:
– Echo.A

Aquí tenemos la misma tarea Echo del primer ejemplo, pero en el trabajo a hemos agregado un campo de configuración. Este campo de configuración toma un mapa, y esto se puede usar para sobrescribir campos del mismo nombre en las tareas que ha definido. Como aquí estamos sobrescribiendo el campo del mensaje en todas nuestras tareas, veremos algo diferente cuando ejecutemos el trabajo-a.

$ mule -f ruta / a / mule.yaml job-a
Otro mensaje para la consola

Ahora, dado que el campo de mensaje de nuestra tarea Echo se ha sobrescrito, vemos que la mula imprime "Otro mensaje para la consola". Es posible que ofrezcamos formas más sofisticadas para sobrescribir configuraciones de tareas en el futuro, pero por ahora es importante tener cuidado al seleccionar los campos que desea sobrescribir para que no vea consecuencias no deseadas en sus trabajos.

Otra cosa que puede hacer en una configuración de trabajos es establecer valores utilizando las variables de entorno de su sistema.

Tareas:
– tarea: eco
nombra un
mensaje: Ajobs:
trabajo-a:
configs:
mensaje: $ {ECHO_A}
Tareas:
– Echo.A

Ahora nuestra tarea Eco imprimirá el contenido de la variable de entorno ECHO_A.

$ export ECHO_A = 'Mensaje para la consola'
$ mule -f ruta / a / mule.yaml job-a
Mensaje para la consola

¡Ahora que podemos usar trabajos para parametrizar tareas, veamos cómo podemos usar otras tareas para ejecutar nuestras tareas!

Resultados de tareas

Tareas:
– tarea: eco
nombra un
mensaje: otro mensaje para la consola
– tarea: eco
nombre: B
mensaje: trabajos '{{Echo.A.outputs.message}}':
trabajo-b:
Tareas:
– Echo.A
– Eco.B

Cada vez que se ejecuta una tarea, produce un diccionario de resultados y los almacena en la memoria para las tareas que se ejecutan más adelante en la cadena. Por lo tanto, las tareas posteriores pueden usar los resultados de tareas anteriores utilizando el patrón '{{task_id.outputs.field}}'. En este ejemplo, tenemos la tarea Echo.B imprimiendo el mensaje que Echo.A envió. Por lo tanto, cuando ejecutamos job-b, vemos:

$ mule -f ruta / a / mule.yaml job-b
Otro mensaje para la consola
Otro mensaje para la consola

Tenga en cuenta que esto también funciona con dependencias también. El único requisito para que una tarea lea los resultados de otra tarea es que la tarea a la que se hace referencia ya se ha ejecutado.

Conclusión

Estas son las características clave del lenguaje Mule yaml. Creemos que este marco nos permitirá desarrollar tuberías consistentes, confiables y portátiles para nuestro producto principal y todos nuestros SDK compatibles. Nuestra lista actual de tareas disponibles se documenta aquí. ¡Siéntase libre de probar sus nuevas habilidades con algunas tareas más útiles!