Pruebas de infraestructura como código con Pulumi. Parte 2

Hola a todos. Hoy compartimos con ustedes la parte final del artículo «Pruebas de infraestructura como código con Pulumi», cuya traducción ha sido preparada específicamente para los estudiantes del curso «Prácticas y herramientas de DevOps».

Pruebas de infraestructura como código con Pulumi. Parte 2

Pruebas de despliegue

El estilo de prueba tratado es un enfoque poderoso, que nos permite llevar a cabo pruebas de caja blanca para verificar el interior del funcionamiento de nuestro código de infraestructura. Sin embargo, limita un poco lo que podemos comprobar. Las pruebas se ejecutan en función de un plan de despliegue en memoria, creado por Pulumi antes del despliegue directo, por lo que el propio despliegue no puede ser probado. Para tales casos, Pulumi tiene un marco de pruebas de integración. ¡Y estos dos enfoques funcionan muy bien juntos!

El marco de pruebas de integración de Pulumi está escrito en Go, y es precisamente con él que probamos la mayor parte de nuestro código interno. Si el enfoque de pruebas modulares mencionado anteriormente se parecía más a la prueba de caja blanca, las pruebas de integración son de caja negra. (También hay opciones para pruebas internas exhaustivas). Este marco fue creado para tomar un programa completo de Pulumi y realizar varias operaciones del ciclo de vida, como desplegar un nuevo stack desde cero, actualizarlo con variaciones y eliminarlo, posiblemente varias veces. Los ejecutamos regularmente (por ejemplo, durante la noche) y como pruebas de estrés.

(Estamos trabajando en que, capacidades similares de pruebas de integración estén en el SDK nativo de los lenguajes. Puedes usar el marco de pruebas de integración de Go independientemente del lenguaje en el que esté escrita tu programa de Pulumi).

Al ejecutar el programa con este marco puedes verificar lo siguiente:

  • El código de tu proyecto es sintácticamente correcto y funciona sin errores.
  • La configuración del stack y la interpretación de secretos funcionan correctamente.
  • Tu proyecto puede ser desplegado exitosamente en el proveedor de nube que elijas.
  • Tu proyecto puede ser actualizado con éxito desde su estado inicial hasta N otros estados.
  • Tu proyecto puede ser destruido y eliminado con éxito de tu proveedor de nube.

Como veremos pronto, este marco también se puede utilizar para realizar validaciones en tiempo de ejecución.

Una prueba de integración simple

Para ver esto en acción, observaremos el repositorio pulumi/examples, ya que nuestro equipo y la comunidad de Pulumi lo utilizan para probar sus propias solicitudes de extracción, confirmaciones y compilaciones nocturnas.

A continuación se presenta una prueba simplificada de nuestro ejemplo, que provisiona un bucket de S3 y algunos otros objetos:

example_test.go:

paquete test
 
import (
    "os"
    "path"
    "testing"
 
    "github.com/pulumi/pulumi/pkg/testing/integration"
)
 
func TestExamples(t *testing.T) {
    awsRegion := os.Getenv("AWS_REGION")
    if awsRegion == "" {
        awsRegion = "us-west-1"
    }
    cwd, _ := os.Getwd()
    integration.ProgramTest(t, &integration.ProgramTestOptions{
        Quick:       true,
        SkipRefresh: true,
        Dir:         path.Join(cwd, "..", "..", "aws-js-s3-folder"),
        Config: map[string]string{
            "aws:region": awsRegion,
        },
    })
}

Esta prueba pasa por el ciclo de vida básico de creación, modificación y destrucción de un stack para la carpeta aws-js-s3-folder. Tomará alrededor de un minuto informar sobre el resultado de la prueba:

$ go test .
PASS
ok      ... 43.993s

Hay muchos parámetros para personalizar el comportamiento de estas pruebas. La lista completa de opciones se puede ver en la estructura ProgramTestOptions. Por ejemplo, puede configurar el endpoint de Jaeger para trazas (Tracing), indicar que espera que la prueba falle en pruebas negativas (ExpectFailure), aplicar una serie de "ediciones" al programa para transiciones de estado secuenciales (EditDirs) y mucho más. Veamos cómo usarlas para verificar el despliegue de una aplicación.

Verificando las propiedades de los recursos

La integración mencionada anteriormente garantiza que nuestro programa "funcione" — no se caiga. Pero, ¿qué pasaría si quisiéramos verificar las propiedades del stack resultante? Por ejemplo, si ciertos tipos de recursos fueron (o no fueron) provisionados y que tienen ciertos atributos.

Parámetro ExtraRuntimeValidation para ProgramTestOptions nos permite observar el estado registrado por Pulumi después del despliegue (estado post-despliegue), para que podamos realizar verificaciones adicionales. Esto incluye una instantánea completa del estado del stack resultante, incluyendo la configuración, los valores de salida exportados, todos los recursos y los valores de sus propiedades, así como todas las dependencias entre recursos.

Para ver un ejemplo básico de esto, verifiquemos que nuestro programa crea un Bucket S3:

  integration.ProgramTest(t, &integration.ProgramTestOptions{
        // como antes...
        ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
            var foundBuckets int
            for _, res := range stack.Deployment.Resources {
                if res.Type == "aws:s3/bucket:Bucket" {
                    foundBuckets++
                }
            }
            assert.Equal(t, 1, foundBuckets, "Se esperaba encontrar un solo bucket de AWS S3")
        },
    })

Ahora, cuando ejecutemos go test, no solo pasará por una serie de pruebas de ciclo de vida, sino que, después de desplegar con éxito la pila, realizará una verificación adicional del estado resultante.

Pruebas de tiempo de ejecución

Hasta ahora, todas las pruebas han sido exclusivamente sobre el comportamiento durante el despliegue y sobre el modelo de recursos de Pulumi. ¿Qué hacer si quieres verificar que tu infraestructura preparada realmente funciona? Por ejemplo, que la máquina virtual está activa, el bucket de S3 contiene lo que esperamos, etc.

Probablemente ya adivinaste cómo hacerlo: la opción ExtraRuntimeValidation para ProgramTestOptions — es una excelente oportunidad para ello. En este punto, ejecutas una prueba Go arbitraria con acceso al estado completo de los recursos de tu programa. Este estado incluye información como direcciones IP de máquinas virtuales, URLs y todo lo necesario para interactuar realmente con tus aplicaciones e infraestructura en la nube obtenidas.

Por ejemplo, nuestro programa de prueba exporta la propiedad webEndpoint del bucket llamado websiteUrl, que representa la URL completa a través de la cual podemos acceder al documento index. Aunque podríamos buscar en el archivo de estado para encontrar bucket y leer esta propiedad directamente, en muchos casos nuestras pilas exportan propiedades útiles, como esta, que es conveniente usar para la verificación:

integration.ProgramTest(t, &integration.ProgramTestOptions{
            // como antes ...
        ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
            url := "http://" + stack.Outputs["websiteUrl"].(string)
            resp, err := http.Get(url)
            if !assert.NoError(t, err) {
                return
            }
            if !assert.Equal(t, 200, resp.StatusCode) {
                return
            }
            defer resp.Body.Close()
            body, err := ioutil.ReadAll(resp.Body)
            if !assert.NoError(t, err) {
                return
            }
            assert.Contains(t, string(body), "¡Hola, Pulumi!")
        },
    })

Al igual que nuestras verificaciones de tiempo de ejecución anteriores, esta verificación se ejecutará inmediatamente después de levantar la pila, y todo esto en respuesta a una simple llamada go test. Y esto es solo la punta del iceberg: todas las capacidades de prueba de Go están disponibles para que las escribas en tu código.

Integración continua de infraestructura

Es útil poder ejecutar pruebas en un portátil cuando se realizan muchos cambios en la infraestructura, para verificación antes de enviarlos a revisión de código. Pero nosotros y muchos de nuestros clientes probamos la infraestructura en diferentes etapas del ciclo de desarrollo:

  • En cada pull request abierto para pruebas antes de la fusión.
  • En respuesta a cada commit, para verificar que la fusión se haya realizado correctamente.
  • Periódicamente, por ejemplo, durante la noche o semanalmente para pruebas adicionales.
  • Como parte de pruebas de rendimiento o pruebas de estrés, que generalmente se ejecutan durante períodos prolongados y ejecutan pruebas en paralelo y/o despliegan el mismo programa varias veces.

Para cada uno de ellos, Pulumi admite la integración con tu sistema de integración continua favorito. Con la integración continua, esto te proporciona la misma cobertura de pruebas para tu infraestructura como para el software aplicacional.

Pulumi tiene soporte para sistemas CI comunes. Algunos de ellos son:

Para obtener más información, consulta la documentación sobre Entrega Continua.

Entornos efímeros

Una característica muy potente que se presenta es la capacidad de desplegar entornos efímeros exclusivamente para pruebas de aceptación. La concepción de proyectos y pilas Pulumi está diseñada de tal manera que permite desplegar y eliminar entornos completamente aislados e independientes, todo con unos pocos comandos simples de CLI o mediante un marco de pruebas de integración.

Si utilizas GitHub, Pulumi ofrece un GitHub App, que te ayudará a conectar las pruebas de aceptación a los pull requests dentro de tu pipeline CI. Simplemente instala la aplicación en tu repositorio de GitHub, y Pulumi en tu CI y se añadirá información sobre la vista previa de la infraestructura, actualizaciones y resultados de las pruebas a los pull requests:

Pruebas de infraestructura como código con Pulumi. Parte 2

Al utilizar Pulumi para sus pruebas de aceptación principales, tendrá nuevas oportunidades de automatización que mejorarán el rendimiento del equipo y proporcionarán confianza en la calidad de los cambios.

Summary

En este artículo, hemos visto que, al utilizar lenguajes de programación de propósito general, tenemos acceso a muchos métodos de desarrollo de software que han sido útiles en el desarrollo de nuestras aplicaciones. Incluyen pruebas unitarias, pruebas de integración, así como su interacción para realizar pruebas extensivas en tiempo de ejecución. Las pruebas se pueden ejecutar fácilmente bajo demanda o en su sistema CI.

Pulumi — es un software de código abierto, gratuito para usar y que funciona con sus lenguajes de programación y nubes favoritos — pruébalo hoy!

→ Primera parte

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster