Automatización del ALM de desarrollo en Microsoft Dynamics 365 for Finance and Operations

Ya he escrito unos cuantos posts sobre la ALM (Application Lifecycle Management) de desarrollo  para Dynamics 365 for Finance and Operations in the past:

La posibilidad de hacer CI/CD real es una de mis cosas favoritas de MSDyn365FO, pasar del «¿Qué control de código?» a «O usas control de código o muere» ha sido una maravilla. Nunca me cansaré de decirlo.

Además el post acaba con un extra bonus!

¡Más automatización!

Ya he explicado antes como automatizar las builds, crear builds de CI y crear las releases en Azure DevOps, así que de lo que quiero hablar en este post es de añadir un poco más de automatización.

Builds

En la definición de build vamos a la pestaña «Triggers» y activamos las builds programadas:

Esto va a lanzar una build automaticamente los días que quieras y a la hora que le digas. En el ejemplo se lanza todos los días entre semana a las 16.30h. Pero… ¿todos los días? No. El check «Only schedule builds if the source or pipeline has changed» hace que sólo se lance la build si ha habido cambios en el código, así que si un día no hay changesets nuevos no se lanza la build.

Releases

Builds listas, a ver qué podemos hacer con las releases:

La release de la imagen de arriba es la que se lanza automáticamente después de la build que he creado en el primer paso. Para esta release he añadido lo siguiente:

El disparador de CD está activo, lo que hace que cada vez que una build termina se ejecuta automáticamente. Sin necesidad de definir una programación horaria, pero también se podría hacer.

Como véis, la pantalla de la programación es exactamente igual que en las builds, incluso el check de cambios está ahí. Se pueden usar cualquiera de estas dos formas, CD o release programada, depende de las necesidades del proyecto o equipo.

Con estos dos pequeños pasos tenemos la estrategia de CI y CD completamente automatizada, y la actualización del entorno de UAT cada noche para tener los cambios hechos durante el día listos para testear, sin humanos de por medio!

Pero a mi me gusta un poco de toque humano

Si no te gusta no saber cuando se actualiza un entorno… bueno eso es IMPOSIBLE porque LCS te Spamea para que no te pierdas ni un despliegue. Pero si lo que no quieres es ser completamente reemplazado por robots puedes añadir aprobaciones a tu flujo de release:

Haciendo clic en el icono izquierdo de relámpago + persona puedes configurar los aprobadores, una persona o grupo (cosa que es muy práctica), y el tipo de aprobación (única o múltiple) y timeout. También recibirás un correo con un enlace al formulario de aprobación:

¡E incluso puedes posponer el despliegue! ¡Todo es fabuloso!

Extra bonus!

Un pequeño consejo. Imaginemos que tenemos esta release:

Esto actualizaría 3 entornos, pero también haría 3 subidas del Deployable Package a LCS. ¿No estaría bien poder hacer una única subida y que los despliegues se hicieran usando ese archivo? Sí, pero no podemos pasar el valor de la variable de salida del stage de subida a los demas stages 🙁 Eso desgraciadamente es así. Pero podemos hacer algo con un poco de ayuda de nuestro amigo Powershell!

Actualizar una variable en uan release

Lo que necesitamos es crear una variable en la definición de release y poner su ámbito como «Release»:

Luego, por cada stage que tengamos, tenemos que activar este check en el agent job:

Luego explicaré por qué. Ahora sólo tenemos que actualizar esta variable una vez subido el DP a LCS. Añadimos un Powershell de tipo inline después del paso de la subida y hacemos esto:

Necesitamos cambiar lo siguiente:

  • Línea 2: $assetId= «$(GoldenUpload.FileAssetId)». Cambiar $(GoldenUpload.FileAssetId) por tu variable de salida.
  • Línea 6: $ReleaseVariableName = ‘axzfileid’. Cambiar axzfileid por tu variable de Release.

Y listos. Este script usa la API REST de Azure DevOps para actualizar el valor de la variable con el file id, y hemos activado el check del token de OAuth para no tener que autenticarnos con ningún usuario. Esto no es idea mía, lo he hecho gracias a este post del blog de Stefan Stranger’s.

Ahora en los stages de despliegue recuperamos el valor de la variable así:

No os olvidéis los ( ) o no funcionará!!!

Y con este pequeño cambio tenemos una release como esta:

Con una única subida del DP a LCS y múltiples despliegues usando el archivo subida en el primer stage. Y con aprobaciones, y retrasos y correos y todo!

Ahora la mala noticia

La mala noticia es que, de momento, en los entornos de tipo self-service no se puede automatizar el despliegue. Y obviamente en los entornos de producción tampoco se puede automatizar nada, esa parte sigue siendo 100% manual.

 

Recuento de inventario con AI Builder

Este pasado fin de semana he participado en mi tercer 365 Saturday, esta vez en Barcelona, como speaker. Como podéis ver en el título mi charla ha tratado sobre la creación de diarios de recuento usando la IA y la Power Platform.

El evento ha sido (como siempre) genial, pero mi sesión me ha dejado con un sabor agridulce porque no he podido mostrar la funcionalidad completa de la app por culpa de problemas técnicos estúpidos (que eran estúpidos pero mi culpa) que solucioné en dos minutos después de la sesión.

Yo arreglando el problema DESPUÉS de la sesión

Pero bueno, gracias a todos los que asistieron a mi charla y lo siento por la cagada. Gracias también a la organización, así como a los demás speakers t al equipo de Axazure.

Contando con IA

¿De qué trataba mi sesión? Nada original. Si habéis visto la keynote de inauguración del pasado MBAS hubo una parte sobre un distribuidor de Pepsi que estaba usando AI Builder para escanear sus expositores y analizar cómo evolucionaban las ventas (más o menos). Mi PowerApp usa AI Builder para contar objetos (luego veréis cuáles) y con eso crea un diario de recuento en Dynamics 365 for Como-se-llame-pero-el-ERP.

Al final mi intención principal con esto es demostrar que podemos usar toda la Power Platform con MSDyn365FO, no solo Power BI, y que nos puede ayudar en los proyectos. Porque los que trabajamos con AX a veces estamos como:

Esto lo encontré en Twitter y añadí los logos, pero no recuerdo a quién se lo robé 🙁

AI Builder

AI Builder es una herramienta para la Power Platform que añade funcionalidad a PowerApps y Flow. Y es muy muy muy fácil de configurar y usar.

Ahora mismo AI Builder está formado por 4 modelos distintos:

  • Predicción: responde preguntas binarias como «¿Renovará mi cliente la suscripción?» o «¿Qué cliente no pagará a tiempo?».
  • Clasificación de texto: extracción de datos de texto. Devuelve un % como respuesta, 95% Bueno, 76% rápido, etc.
  • Procesamiento de formularios: extracción de datos en pares clave-valor. Por ejemplo, extraer datos de documentos (tiene que ser siempre el mismo documento).
  • Detección de objetos: detecta objetos en imágenes. Este es el modelo que usé yo.

De estos cuatro modelos solo el de predicción esta en GA, los otros siguen en preview. Además hay 5 modelos pre-entrenados disponibles:

Si quieres saber más sobre AI Builder hay unhands-on-lab con todos los recursos necesarios para crear tu App usando cualquiera de los 4 modelos.

Y si necesitas un entorno de PowerApps apúntate al PowerApps Community Plan para obtener un entorno gratis en el que podrás usar PowerApps y FLow (y el CDS). Si no te has apuntado todavía, ¡ya tardas!

IA 101

Para explicar cómo funciona esto primero tengo que explicar un poco de conceptos básicos de AI y ML. Pero muy básicos, del palo tan básicos que pueda salir yo delante de gente y explicarlo. Si quieres ver esto mejor explicado mira este video de Channel 9 sobre modelos, es de donde aprendí todo.

En el desarrollo clásico cuando solucionamos un problema lo que hacemos es pasar datos y una función que hemos creado por un proceso y obtenemos un resultado como salida. El equivalente a esto en machine learning es que introducimos datos y las soluciones a un problema y lo que obtenemos es una función que soluciona el problema al que responden las soluciones que hemos introducido. Esta función es tu modelo de ML.

¿Qué más tenemos que saber acerca de lo modelos? Bueno, básicamente que la cantidad de datos con la que alimentamos a nuestro modelo es directamente proporcional a la calidad de las respuestas/soluciones que obtendremos. AI Builder nos pide un mínimo de 15 imágenes para el modelo de detección de objetos. Con 15 imágenes lo que tendremos es un modelo mierdoso, que detectará lo que queremos, pero que también detectará casi como como lo que estamos intentando identificar, porque la muestra es demasiado pequeña.

La PatatApp

¿Por qué este nombre? Pues es que cuento patatas con la app. ¿Y por qué patatas? Porque me encantan, son muy versátiles (puedes hacer tortilla, freírlas, vodka, etc.) y porque contar palés es muy aburrido.

Lo que mi PowerApp hace es detectar las patatas, luego puedo elegir entre usar un diario existente o crear uno nuevo, selecciono un artículo con sus dimensiones de inventario y, finalmente, creo una línea en el diario en AX. He hecho un vídeo muy corto mostrándolo.

Fácil, ¿verdad? Detecto 3 patatas usando AI Builder, selecciono la empresa, creo un diario nuevo y completo el artículo y dimensiones. Finalmente se crea la línea y la tenemos en MSDyn365FO.

Ni brujería ni magia por ningún lado. (ODIO lo de «magia» cuando hablamos de desarrollo o lo que sea, porque parece que se ha hecho sin esfuerzo. Fin de la pataleta.) Para crear la cabecera y la línea del diario estoy usando dos Flows que obtienen los datos de la PowerApp y los crean en Dynamics 365:

¿Véis? No hay magia, sólo un Flow.

Mi compañero Hugo de Jesús me dijo de usarl la función Patch en el data source pero: 1) La app estaba terminada 2) Me lo dijo la semana antes. Pero seguramente hubiera funcionado bien también.

Como véis es una app muy sencilla, la primera versión la tuve lista en cuatro horas, con AI Builder y los Flows es muy rápido.

Modelo mierder vs Modelo no-tan-mierder

Quiero terminar con hechos reales y datos importantes. ¿Recordáis el mínimo de imágenes que pide AI Builder? 15 nada más. Esto es lo que pasa cuando tu modelo está formado por 20 imágenes de solitarias patatas:

Si tu modelo apesta seguirá detectando las patatas en una imagen, pero prácticamente todo será, literalmente, una patata.

Después entrené una segunda versión del modelo, con 40 imágenes de patatas con gatos, personas, otras verduras, etc. El resultado es mucho mejor y sigue detectando patatas:

Quiero agradecer a cazapelusas por hacerme todas las imágenes de las patatitas y por el rediseño de la PowerApp, deberíasi ver la V1. Por favor, adoptad un diseñador gráfico, hará vuestra vida más bonita.

Ninguna patata fue dañada en la creación de esta PowerApp.

Configurar la exportación de Entity Store a Azure Data Lake

Empezar este post es fácil, porque muchos nos podemos preguntar:

¿Qué es un Data Lake?

Pescando en un Data Lake. Cortesía de cazapelusas.

Un Data Lake no es un producto de Azure, es un concepto que hace referencia a un lugar donde se guardan datos, sin importar si son estructurados o no. Su único propósito es guardar los datos sin procesar para que estén listos para ser consumidos por otros sistemas. Es como un lago que recibe y almacena el agua de sus afluentes, solo que con datos en vez de agua.

En Azure el Data Lake es un blob que guarda los datos. Y estos datos pueden venir de Microsoft Dynamics 365 for Finance o Supply Chain Management (voy a acabar loco con los cambios de nombre de Axapta 7) o de otros orígenes.

Actualmente, y desde el PU23, #MSDyn365FO (#MSDyn365F ? o #MSDyn365SCM ?) soporta oficialmente la exportación del Entity Store a un Azure Data Lake storage Gen1, pero la compatibilidad con el Data Lake Storage Gen2 está en preview privada con los Data Feeds, que nos permitirán exportar entidades y tablas (SÍ!) en casi tiempo real. Si queréis saber más echadle un ojo al grupo Data Management, Data Entities, OData and Integrations de Yammer del Insider Program (y si no estáis apuntados, deberíais).

Comparación vs. BYOD

Lo primero de lo que nos vamos a dar cuenta es el precio. El almacenamiento es más barato que una base de datos, incluso si es una sola base de datos en una instancia SaaS en Azure SQL. Por ejemplo, un Blob de 1GB en Azure cuesta 18.22€ al mes.

Y la DB más simple, una Azure SQL Gen 4 con 1 vCore cuesta 160,53€ al mes. Casi 10 veces más.

¿Y el redimiento? Esto que voy a decir es una conclusión de la observación, no un test real de rendimiento, pero los datos se transfieren muy rápido. Y es rápido porque en un Data Lake los datos se mandan sin procesar, no hay transformación de los datos hasta que se consumen (ETL para una DB, ELT para un Data Lake) así que se pierde menos tiempo hasta que los datos llegan a su destino. Esto no tiene un impacto real con conjuntos de datos pequeños, pero sí con los grandes.

Configuración

El proceso para exportar el Entity Store al Data Lake es bastante sencillo y está bien documentado (pero no actualizado del todo) en los docs. Lo explicaré paso a paso.

Crear una cuenta de almacenamiento en Azure

En Azure vamos a las cuentas de almacenamiento y creamos una nueva como en la imagen inferior:

Nos aseguramos de deshabilitar el almacenamiento Gen2:

Y ya podemos crear la cuenta. Cuando esté lista vamos a Access Keys y copiamos la cadena de conexión:

Azure Key Vault

El siguiente paso es crear el Key VAult. Para este paso debemos seleccionar la misma región que la de nuestra instancia de Dynamics 365:

Cuando el Key Vaul esté listo vamos al recurso y creamos un nuevo secreto. Pegaremos la cadena de conexión de la cuenta de almacenamiento y pulsamos crear:

Crear un registro de App de AAD

Le damos un nombre a la App, seleccionamos los tipos de cuenta soportadas que necesitemos y rellenamos la URL con la dirección de nuestra instancia de #MSDyn365FO:

La registramos y ahora tenemos que añadir la API de Azure Key Vault para la app como en la imagen:

Seleccionamos la API y añadimos el permiso delegado de user_impersonation:

No os olvidéis de dar permisos con el botón de encima (debe hacerlo un admin de Azure). Ahora vamos a los secretos, creamos uno y copiamos el valor que nos da. Cuando se cierre esta pestaña no podremos ver el valor del secreto, así que aseguráos de haberlo copiado!

Configurar el Key Vault

Volvemos al Key Vault que hemos creado antes y vamos a Access policies. Creamos una nueva:

Necesitamos seleccionar Get y List para permisos de clave y secreto:

Pulsamos select principal y aquí añadimos la App de AAD que hemos creado en el tercer paso:

Añádela y no te olvides de darle a guardar en la página de las políticas de acceso!!

Configurar MSDyn365F… y O o SCM o como sea que se llame este mes

Vamos a Administración del sistema -> Configurar -> Parámetros del sistema y ahí a la pestaña Conexiones de datos. Aquí tenemos 4 campos que hay que rellenar. El Application ID es el Application ID de la App de AAD (obvio) y el Application Secret  el secreto de esa App. Esta parte está bastante clara.

El DNS name es la URL del Key Vault, y el Secret name es el nombre del secreto que hemos creado en el Key Vault con la cadena de conexión.

Una vez está todo configurado podemos pulsar los botones de prueba y, si habéis seguido todos los pasos, deberían saliros estos mensajes:

Si cualquiera de las validaciones falla simplemente borraría todos los recursos y empezaría de cero.
Ahora, los dos checkbox que tenemos al lado de los campos:
  • Enable Data Lake integration: activa el push de datos del entity store a la cuenta de almacenamiento que hemos creado al principio y que es el principal propósito de este post.
  • Trickle update Data Lake: hace actualizaciones después de que cambien los datos (Trickle Feed).

Configurar Entity Store

Para acabar, vamos al Entity Store (en Administración del sistema-> Configurar -> Entity Store) y activamos el refresco de las entidades que queremos que hidraten el Data Lake (me encanta, parece que es el término correcto para referirse a mandar datos al Data Lake):

Y listo, nuestros datos se están mandando a un Blob de Azure:

Las entidades se guardan cada una en una carpeta, y dentro de cada carpeta hay otra carpeta por cada medida de esa entidad, y dentro un CSV con los datos.

Ahora podemos consumir estos datos desde Power BI con el conector de blob, o alimentar a Azure Data Factory o lo que quieras, porque ese es el propósito del Data Lake.