Testen von Infrastructure as Code mit Pulumi. Teil 2

Hallo zusammen. Heute teilen wir mit Ihnen den letzten Teil des Artikels. „Infrastruktur als Code testen mit Pulumi“, dessen Übersetzung speziell für Kursteilnehmer erstellt wurde „DevOps-Praktiken und -Tools“.

Testen von Infrastructure as Code mit Pulumi. Teil 2

Bereitstellungstests

Dieser Teststil ist ein leistungsstarker Ansatz und ermöglicht uns die Durchführung von White-Box-Tests, um die interne Funktionsweise unseres Infrastrukturcodes zu testen. Allerdings schränkt es die Möglichkeiten, die wir testen können, etwas ein. Die Tests werden auf der Grundlage des von Pulumi vor der eigentlichen Bereitstellung erstellten In-Memory-Bereitstellungsplans durchgeführt und daher kann die Bereitstellung selbst nicht getestet werden. Für solche Fälle verfügt Pulumi über ein Integrationstest-Framework. Und diese beiden Ansätze passen hervorragend zusammen!

Das Pulumi-Integrationstest-Framework ist in Go geschrieben, und so testen wir den Großteil unseres internen Codes. Während der zuvor diskutierte Unit-Test-Ansatz eher einem White-Box-Test ähnelte, ist der Integrationstest eine Black-Box. (Es gibt auch Optionen für strenge interne Tests.) Dieses Framework wurde erstellt, um ein vollständiges Pulumi-Programm zu nehmen und verschiedene Lebenszyklusoperationen darauf auszuführen, wie z. B. das Bereitstellen eines neuen Stacks von Grund auf, das Aktualisieren mit Variationen und das Löschen, möglicherweise mehrmals . Wir führen sie regelmäßig (zum Beispiel nachts) und als Stresstests durch.

(Wir wir arbeiten daran, sodass ähnliche Integrationstestfunktionen im nativen SDK der Sprachen verfügbar sind. Sie können das Go-Integrationstest-Framework unabhängig von der Sprache verwenden, in der Ihr Pulumi-Programm geschrieben ist.

Wenn Sie das Programm mit diesem Framework ausführen, können Sie Folgendes überprüfen:

  • Ihr Projektcode ist syntaktisch korrekt und läuft fehlerfrei.
  • Die Konfigurationseinstellungen für Stack und Secrets funktionieren und werden korrekt interpretiert.
  • Ihr Projekt kann erfolgreich beim Cloud-Anbieter Ihrer Wahl bereitgestellt werden.
  • Ihr Projekt kann erfolgreich vom Ausgangszustand auf N andere Zustände aktualisiert werden.
  • Ihr Projekt kann erfolgreich zerstört und von Ihrem Cloud-Anbieter entfernt werden.

Wie wir gleich sehen werden, kann dieses Framework auch zur Durchführung einer Laufzeitvalidierung verwendet werden.

Einfacher Integrationstest

Um dies in Aktion zu sehen, schauen wir uns das Repository an pulumi/examples, da unser Team und die Pulumi-Community es verwenden, um unsere eigenen Pull-Anfragen, Commits und nächtlichen Builds zu testen.

Nachfolgend finden Sie einen vereinfachten Test von uns Beispiel, das den S3-Bucket und einige andere Objekte bereitstellt:

example_test.go:

package 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,
        },
    })
}

Dieser Test durchläuft den grundlegenden Lebenszyklus des Erstellens, Änderns und Zerstörens eines Stapels für einen Ordner aws-js-s3-folder. Die Meldung einer bestandenen Prüfung dauert etwa eine Minute:

$ go test .
PASS
ok      ... 43.993s

Es gibt viele Möglichkeiten, das Verhalten dieser Tests anzupassen. Vollständige Liste der Optionen anzeigen. in der Struktur ProgramTestOptions. Beispielsweise können Sie den Jaeger-Endpunkt so konfigurieren, dass er verfolgt (Tracing), geben Sie an, dass Sie davon ausgehen, dass der Test fehlschlägt, wenn der Test negativ ausfällt (ExpectFailure), wenden Sie eine Reihe von „Änderungen“ am Programm an, um einen sequentiellen Zustandsübergang zu erreichen (EditDirs) und vieles mehr. Sehen wir uns an, wie Sie sie zum Testen Ihrer Anwendungsbereitstellung verwenden.

Ressourceneigenschaften prüfen

Die oben besprochene Integration stellt sicher, dass unser Programm „funktioniert“ – es nicht abstürzt. Was aber, wenn wir die Eigenschaften des resultierenden Stapels überprüfen möchten? Beispielsweise, dass bestimmte Arten von Ressourcen bereitgestellt wurden (oder nicht) und dass sie über bestimmte Attribute verfügen.

Parameter ExtraRuntimeValidation für ProgramTestOptions ermöglicht es uns, den von Pulumi aufgezeichneten Status nach der Bereitstellung einzusehen, damit wir zusätzliche Überprüfungen durchführen können. Dazu gehört eine vollständige Momentaufnahme des Status des resultierenden Stacks, einschließlich Konfiguration, exportierter Ausgabewerte, aller Ressourcen und ihrer Eigenschaftswerte sowie aller Abhängigkeiten zwischen Ressourcen.

Um ein einfaches Beispiel dafür zu sehen, überprüfen wir, ob unser Programm eines erstellt S3-Eimer:

  integration.ProgramTest(t, &integration.ProgramTestOptions{
        // as before...
        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, "Expected to find a single AWS S3 Bucket")
        },
    })

Wenn wir nun go test ausführen, durchläuft es nicht nur eine Reihe von Lebenszyklustests, sondern führt nach erfolgreicher Bereitstellung des Stacks auch eine zusätzliche Prüfung des resultierenden Status durch.

Laufzeittests

Bisher ging es bei allen Tests ausschließlich um das Bereitstellungsverhalten und das Pulumi-Ressourcenmodell. Was ist, wenn Sie überprüfen möchten, ob Ihre bereitgestellte Infrastruktur tatsächlich funktioniert? Beispielsweise, dass die virtuelle Maschine läuft, der S3-Bucket das enthält, was wir erwarten, und so weiter.

Sie haben vielleicht schon erraten, wie das geht: Option ExtraRuntimeValidation für ProgramTestOptions - Das ist eine großartige Gelegenheit dafür. An diesem Punkt führen Sie einen benutzerdefinierten Go-Test mit Zugriff auf den vollständigen Status der Ressourcen Ihres Programms durch. Dieser Status umfasst Informationen wie IP-Adressen virtueller Maschinen, URLs und alles, was für die tatsächliche Interaktion mit den resultierenden Cloud-Anwendungen und der Infrastruktur erforderlich ist.

Unser Testprogramm exportiert beispielsweise die Eigenschaft webEndpoint Eimer genannt websiteUrl, das ist die vollständige URL, unter der wir die Konfiguration abrufen können index document. Obwohl wir in der Staatsdatei stöbern könnten, um es herauszufinden bucket und lesen Sie diese Eigenschaft direkt, aber in vielen Fällen exportieren unsere Stacks nützliche Eigenschaften wie diese, die wir für die Überprüfung praktisch finden:

integration.ProgramTest(t, &integration.ProgramTestOptions{
            // as before ...
        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), "Hello, Pulumi!")
        },
    })

Wie unsere vorherigen Laufzeitprüfungen wird diese Prüfung sofort nach dem Erhöhen des Stapels ausgeführt, alles als Reaktion auf einen einfachen Aufruf go test. Und das ist nur die Spitze des Eisbergs – jede Go-Testfunktion, die Sie in Code schreiben können, ist verfügbar.

Kontinuierliche Infrastrukturintegration

Es ist gut, Tests auf einem Laptop ausführen zu können, wenn viele Änderungen an der Infrastruktur vorgenommen werden, um sie zu testen, bevor sie zur Codeüberprüfung eingereicht werden. Aber wir und viele unserer Kunden testen die Infrastruktur in verschiedenen Phasen des Entwicklungslebenszyklus:

  • In jeder offenen Pull-Anfrage zum Testen vor dem Zusammenführen.
  • Überprüfen Sie als Reaktion auf jedes Commit noch einmal, ob die Zusammenführung korrekt durchgeführt wurde.
  • In regelmäßigen Abständen, beispielsweise nachts oder wöchentlich, für zusätzliche Tests.
  • Als Teil von Leistungs- oder Stresstests, die typischerweise über einen längeren Zeitraum laufen und Tests parallel ausführen und/oder dasselbe Programm mehrmals bereitstellen.

Für jedes davon unterstützt Pulumi die Integration mit Ihrem bevorzugten kontinuierlichen Integrationssystem. Durch die kontinuierliche Integration erhalten Sie so die gleiche Testabdeckung für Ihre Infrastruktur wie für Ihre Anwendungssoftware.

Pulumi unterstützt gängige CI-Systeme. Hier sind einige davon:

Ausführlichere Informationen finden Sie in der Dokumentation zu Kontinuierliche Liefer.

Vergängliche Umgebungen

Eine sehr wirkungsvolle Chance, die sich eröffnet, ist die Möglichkeit, kurzlebige Umgebungen ausschließlich für Akzeptanztestzwecke bereitzustellen. Konzept Projekte und Stapel Pulumi wurde entwickelt, um völlig isolierte und unabhängige Umgebungen einfach bereitzustellen und zu zerstören, alles mit ein paar einfachen CLI-Befehlen oder mithilfe eines Integrationstest-Frameworks.

Wenn Sie GitHub verwenden, bietet Pulumi an GitHub-App, das Ihnen dabei hilft, Akzeptanztests mit Pull-Anfragen innerhalb Ihrer CI-Pipeline zu verbinden. Installieren Sie einfach die Anwendung im GitHub-Repository und Pulumi fügt Ihren CI- und Pool-Anfragen Informationen zu Infrastrukturvorschauen, Updates und Testergebnissen hinzu:

Testen von Infrastructure as Code mit Pulumi. Teil 2

Wenn Sie Pulumi für Ihre Kernabnahmetests verwenden, erhalten Sie neue Automatisierungsmöglichkeiten, die die Teamproduktivität verbessern und Ihnen Vertrauen in die Qualität Ihrer Änderungen geben.

Ergebnis

In diesem Artikel haben wir gesehen, dass uns durch die Verwendung allgemeiner Programmiersprachen viele Softwareentwicklungstechniken zur Verfügung stehen, die sich bei der Entwicklung unserer Anwendungen als nützlich erwiesen haben. Dazu gehören Unit-Tests, Integrationstests und wie sie zusammenarbeiten, um umfangreiche Laufzeittests durchzuführen. Tests können einfach bei Bedarf oder in Ihrem CI-System ausgeführt werden.

Pulumi - Open-Source-Software, kostenlos nutzbar und funktioniert mit Ihren bevorzugten Programmiersprachen und Clouds - Probieren Sie es noch heute aus!

Der erste Teil

Source: habr.com

Kommentar hinzufügen