Blog de Amazon Web Services (AWS)

Herramientas para simplificar la migración hacia Python 3.8

Por Victor Palomo, Arquitecto de Soluciones de Telecomunicaciones en AWS

 

Con la Python Software Foundation determinando el fin de vida de Python 2.7 es imperativo migrar a una versión más reciente de Python (3.8 al momento de la publicación de este post). Estas tareas pueden implicar cambios de diversos tipos, desde el ambiente en el que se ejecuta el código hasta modificaciones en instrucciones de código para mantener la compatibilidad.

La comunidad Python ofrece herramientas para mitigar las tareas que implican este cambio de versión, tales como Pylint y 2to3.

Pylint es una herramienta que permite inspeccionar errores en código Python.

2to3 es un programa que lee código Python 2.x y aplica una serie de transformaciones para permitir su ejecución bajo ambientes de Python 3.x.

Este post describe dos scripts de ejemplo para automatizar la migración de funciones de versión Python 2.7 a Python 3.8 desplegadas en AWS Lambda, el servicio de ejecución de código sin servidores. Se recomienda probar los scripts en ambientes no productivos y ajustarlos a las necesidades de su organización antes de usarlos en ambientes productivos.

 

Sobre el proceso de migración

AWS Lambda es un servicio de cómputo sin servidor que permite ejecutar código sin aprovisionar ni administrar servidores. Lambda permite la definición de funciones que agrupan código con una configuración del ambiente de ejecución aprovisionado al momento de ejecución.

Los scripts aquí descritos apoyan en la migración de funciones Lambda basado en los siguientes pasos:

 

 

I. Revisión de alias y versiones.

Las versiones publicadas de funciones Lambda definen una configuración inmutable para el ambiente y código ejecutado. El uso de un alias permite asignar un nombre a estas versiones publicadas, tales como “dev” o “prod”; por ejemplo, la versión publicada 15 puede tener asignado el alias “prod” para ser utilizada por el aplicativo en producción, mientras que la versión 17 lleva el alias “dev” para ser invocada para pruebas.

En este proceso de migración, se aprovecha el uso de versiones publicadas y se recomienda el uso de alias para simplificar la referencia a dichas versiones.

II. Análisis y corrección de compatibilidad del código.

Python 3.8 cuenta con algunas diferencias en su estructura en comparación a Python 2.7. En esta fase es necesario identificar estas potenciales diferencias para asegurar la compatibilidad del código al momento de ejecutarse en un ambiente con Python 3.8. La comunidad Python ofrece herramientas que ayudan a identificar cambios necesario, tales como pylint  y 2to3. 2to3 en particular, ofrece la posibilidad de modificar código para mantener la compatibilidad con Python 3.8. En el script utilizado, se aprovechará esa capacidad para modificar ciertos aspectos estándar (2to3 permite definir elementos adicionales a modificar).

Una vez identificados y corregidos los elementos de código incompatibles, el código puede ser reinsertado en la función Lambda.

III. Migración de ambientes de ejecución.

La versión de Python utilizada en el ambiente de ejecución de las funciones Lambdas se define a través de la configuración del parámetro run-time. Migrar una función de versión Python 2.7 a Python 3.8 se lleva a cabo a través del cambio del parámetro run-time en la configuración.

IV. Publicado nueva versión y modificación de alias.

Con el código compatible con Python 3.8 y el ambiente modificado para utilizar Python 3.8, es posible publicar una nueva versión para hacer referencia a ese ambiente que permita ejecutar las pruebas de validación necesarias.

 

Automatización de migración de funciones

Los pasos de migración pueden ser automatizados aprovechando herramientas como el AWS CLI, Pylint, 2to3 integrados en un script. Este post describe un ejemplo de ese script.

Prerequisitos

Para utilizar este script, requerirá:

  • Una cuenta
  • Acceso a la consola de AWS con credenciales de administrador.
  • Acceso a una terminal de consola Linux con soporte a BASH 3.2 o superior; en este artículo se describe el uso de AWS CloudShell, el ambiente de ejecución Shell basado en browser para interactuar con servicios AWS.
  • Python 3.8 instalado.
  • Pylint instalado.
  • 2to3 instalado.
  • jq  instalado. Jq es un procesador en línea de comandos para objetos JSON, se utiliza para procesar las respuestas provistas obtenidas a partir del AWS CLI.
  • AWS CLI instalado.

Configuración de AWS CloudShell.

Para fines de prueba, los scripts pueden ser ejecutados en una instancia de CloudShell. CloudShell se inicia con AWS CLI y jq preinstalados, por lo que en esta sección instalará únicamente pylint y 2to3.

Es importante que tome en cuenta las limitantes asociadas descritas en la guía de usuario de CloudShell si planea usar los scripts para múltiples funciones. Un ambiente de desarrollo integrado (IDE por sus siglas en inglés) como Cloud9 es una mejor opción para realizar migración de múltiples funciones.

  1. Navegue a la consola de AWS CloudShell y elija la región en la parte superior derecha donde se encuentran las funciones Lambda con las que trabajará. 

     

  2. CloudShell tomará algunos segundos en activarse. Cuando esté lista, aparecerá una pantalla con una terminal de consola similar a la siguiente: 

     

  3. En la terminal, teclee el siguiente comando para instalar 2to3:

pip3 install 2to3

  1. En la terminal, teclee el siguiente comando para instalar pylint:

pip3 install pylint

  1. Confirme que la instalación fue exitosa:

2to3 -h

pylint -h

  1. En ambos casos, deberá observar la ayuda asociada a esos comandos.

Descarga de scripts

Para utilizar los scripts, requerirá clonar el repositorio y habilitar permisos de ejecución.

  1. Navegue a la consola de AWS CloudShell.
  2. Para instalar el script, clone el repositorio con las herramientas:

git clone https://github.com/aws-samples/aws-lambda-migration-tools-for-python.git

  1. Cambie el directorio de trabajo al folder que se clonó.

cd aws-lambda-migration-tools-for-python

  1. Modifique los permisos para agregar ejecución en ambos scripts:

chmod +x lambda-inventory.sh

chmod +x lambda-migrate.sh

  1. Listo, los scripts se encuentran listos para ser ejecutados.

Generación de inventario

  1. Para generar el inventario, desde la instancia de CloudShell y ubicado en el directorio creado durante la descarga de scripts, teclee:

./lambda-inventory.sh -r [REGION]

Sustituya [REGIÓN] por el identificador de la región en la que trabajará, por ejemplo, us-east-1:

./lambda-inventory.sh -r us-east-1

  1. También es posible especificar funciones puntuales para generar el inventario, por ejemplo, para obtener el invetario asociado a las funciones Lambda “funcion1”, “funcion2” y “funcion3”:

./lambda-inventory.sh -r us-east-1 -f "funcion1 funcion2 funcion3"

  1. El script iterará sobre la lista especificada (o sobre todas las funciones en la cuenta en la región especificada) y mostrará en pantalla la versión, runtime y alias asociados.

 

Migración de funciones Lambda

Para migrar funciones Lambda a Python 3.8, es necesario asociar un tag a la función o funciones Lambda a migrar y especificar el tag utilizado como argumento para el script.  En esta sección, se ejemplifica la migración con una función Lambda ejemplo.

Creación de función Lambda

En esta sección creará una función Lambda para migrar con el apoyo del script.

  1. Navegue a la consola de AWS Lambda. Seleccione la región en la que desee trabajar en la parte superior derecha.
  2. Seleccione la opción Functions desde el panel izquierdo.
  3. Presione el botón Create function en el panel principal.
  4. Seleccione Author from Scratch, ingrese un nombre para la función, “python2function” y escoja Python 2.7 para la opción Runtime

     

  5. Mantenga el resto de parámetros por default y presione el botón Create function.
  6. En la sección Code Source, en el panel izquierdo, presione dos veces en el nombre del archivo py para editar el código. 

     

  7. Sustituya el código por lo siguiente:
import json
def lambda_handler(event, context):
    longvariable = long (1000)
    print longvariable
   
    return {
        'statusCode': 200,
        'body': json.dumps("longvariable type:" + str(type(longvariable)))
    }

En este ejemplo, se introducen dos elementos que son identificados por las transformaciones aplicadas por 2to3, los cuales serán modificados por el script:

  1. Uso de variables tipo long -> Sustituir con int.
  2. Cambio de la expresión print a la función print().

2to3 cuenta con un listado de transformaciones disponibles por default y es posible crear transformaciones personalizadas.

  1. Presione el botón Deploy.
  2. Seleccione la pestaña Test y presione el botón Test

     

  3. Un recuadro verde aparecerá con el mensaje Execution Result: succeded.
  4. Presione en la pestaña Code para volver a esa pantalla.
  5. Navegue a la parte inferior de la pantalla a la sección Runtime Settings y presione el botón Edit

     

  6. Cambie la opción Runtime a Python 3.8 y presione Save

     

  7. Navegue nuevamente a la pestaña Test y presione el botón Test. En esta ocasión el resultado aparecerá en un recuadro rojo con el mensaje Execution result: failed debido a la incompatibilidad del código con Python 3.8.
  8. Navegue a la pestaña Code y reconfigure el runtime nuevamente con Python 2.7: Navegue a la parte inferior de la pantalla a la sección Runtime settings y presione el botón Edit.
  9. Seleccione en el parámetro Runtime Python 2.7 y presione el botón Save.

Asignación Tag de migración

El script puede recibir nombres de funciones o Keys de Tags para identificar las funciones Lambda a migrar. En esta sección asigna un Tag.

  1. En la consola de AWS Lambda dentro de la configuración de la función, seleccione la pestaña Configuration, y luego la categoría Tags. Presione Manage Tags

     

  2. Ingrese los siguientes parámetros:
    1. Key: migrate
    2. Value: True

El tag migrate puede ser cualquier valor elegido, pero asegúrese de que el parámetro value sea True.

  1. Presione Save.

Ejecución script de migración

  1. Vuelva a la consola de CloudShell (si la cerró espere a que esté disponible la terminal).
  2. Cambie el directorio de trabajo al folder que se creo en la descarga de los archivos.

cd aws-lambda-migration-tools-for-python

  1. Teclee:

./lambda-migrate.sh -r [REGION] -t migrate -m

Sustituya [REGIÓN] por el identificador de la región en la que trabajará, por ejemplo, us-east-1:

./lambda-migrate.sh -r us-east-1 -t migrate -m

  1. El script ejecutará los siguientes pasos:
    • Analizar funciones con el tag especificado y runtime Python2.7.
    • Publicar una versión con la configuración existente.
    • Descargar el código de la función, ejecutará la herramienta pylint para generar un reporte del código y ejecutará la herramienta 2to3 para aplicar transformaciones. El reporte se escribe en un folder con nombre igual al tag especificado y un subdirectorio con el nombre de la función.
    • El código resultado de las transformaciones es cargado nuevamente a la función Lambda.
    • Una nueva versión es publicada para el código actualizado (para un total de 2 versiones: la existente en Python 2.7 sin modificaciones y la nueva en Python 3.8 con los ajustes)

 

 

  1. Al finalizar, la función contará con una nueva versión publicada con un runtime Python 3.8 y código con las transformaciones de 2to3.
  2. Actualizar página de función Lambda o entrar de nuevo a la función desde la consola de AWS Lambda , dentro de la configuración de la función, seleccione la pestaña Code. Observará una alerta indicando que el código ha sido modificado, presión OK para cerrar el mensaje. 

     

  3. Navegue a la parte inferior de la pantalla a la sección Runtime settings y confirme que el Runtime ha sido modificado a Python 3.8.
  4. De vuelta a la sección de edición de código, observe las líneas de código modificadas en el archivo py.
  5. Finalmente, desde la pestaña Test, presione el botón Test y confirme la ejecución del código portado en un ambiente Python3.8.

Eliminación modificaciones.

Para regresar la configuración previa de la función, desde la consola de AWS Lambda navegue a la parte inferior de la pantalla a la sección Runtime settings y presione Edit seleccione Python 2.7 como Runtime y presione Save.

Navegue a la pestaña Configuration y a la categoría Tags, presione en el botón Manage tags y presione en el botón Remove para eliminar los tags asociados al script.

Finalmente navegue a la pestaña Versions y elimine la última versión publicada(Python 3.8). Seleccione la que ahora es la última versión publicada (Python 2.7), navegue a la pestaña Code, copie el código asociado al archivo .py y regrese a la función para actualizar el código de la última versión (para funciones que contengan mas de un archivo, es posible que deba repetir individualmente el contenido esos archivos).

 

Conclusión

El script descrito puede asistir en las tareas de migración de funciones de versión Python 2.7 a Python 3.8 para ofrecer un nivel de automatización.

 


Sobre el autor

Victor Palomo es Arquitecto de Soluciones en Amazon Web Services enfocado en la industria de Telecomunicaciones.

 

 

 

 

Sobre los revisores

Ivan Gonzalez es Arquitecto de Soluciones en Amazon Web Services.

 

 

 

 

 

Uriel Ramirez es Arquitecto de Soluciones Senior en Amazon Web Services.