Infrastruktúra tesztelése kódként a Pulumival. 1. rész

Kellemes délutánt barátaim. Egy új áramlás kezdetére számítva az ütemben "DevOps gyakorlatok és eszközök" Megosztunk veletek egy új fordítást. Megy.

Infrastruktúra tesztelése kódként a Pulumival. 1. rész

A Pulumi és az általános célú programozási nyelvek használata az infrastruktúra kódhoz (Infrastructure as Code) számos előnnyel jár: készségek és ismeretek rendelkezésre állása, a kódban előforduló sablonok eltávolítása az absztrakció révén, a csapata számára ismerős eszközök, például IDE-k és linterek. Mindezek a szoftverfejlesztő eszközök nemcsak termelékenyebbé tesznek bennünket, hanem javítják kódunk minőségét is. Ezért teljesen természetes, hogy az általános célú programozási nyelvek használata lehetővé teszi számunkra egy másik fontos szoftverfejlesztési gyakorlat bevezetését - tesztelés.

Ebben a cikkben megvizsgáljuk, hogyan segít a Pulumi az infrastruktúra kódként történő tesztelésében.

Infrastruktúra tesztelése kódként a Pulumival. 1. rész

Miért teszteljük az infrastruktúrát?

Mielőtt belemennénk a részletekbe, érdemes feltenni a kérdést: „Miért teszteljük egyáltalán az infrastruktúrát?” Ennek számos oka van, és íme néhány közülük:

  • Egyedi függvények vagy a programlogika töredékeinek egységtesztelése
  • Ellenőrzi az infrastruktúra kívánt állapotát bizonyos korlátok ellenére.
  • Gyakori hibák észlelése, mint például a tárhely titkosításának hiánya vagy a virtuális gépekhez való védelem nélküli, nyílt hozzáférés az internetről.
  • Az infrastruktúra-kiépítés megvalósításának ellenőrzése.
  • A „programozott” infrastruktúrán belül futó alkalmazáslogika futásidejű tesztelése a működés ellenőrzéséhez a kiépítés után.
  • Amint látjuk, az infrastruktúra tesztelési lehetőségek széles skálája létezik. A Poluminak van mechanizmusa a spektrum minden pontján történő tesztelésre. Kezdjük, és nézzük meg, hogyan működik.

Egységteszt

A Pulumi programokat olyan általános célú programozási nyelveken írják, mint a JavaScript, a Python, a TypeScript vagy a Go. Ezért ezeknek a nyelveknek a teljes ereje, beleértve eszközeiket és könyvtáraikat, beleértve a tesztkeretrendszereket is, a rendelkezésükre áll. A Pulumi többfelhős, ami azt jelenti, hogy bármely felhőszolgáltatótól tesztelhető.

(Ebben a cikkben, annak ellenére, hogy többnyelvű és többfelhős, JavaScriptet és Mochát használunk, és az AWS-re összpontosítunk. Használhatja a Pythont unittest, Go teszt keretrendszer, vagy bármilyen más teszt keretrendszer, amit szeretsz. És természetesen a Pulumi remekül működik az Azure-ral, a Google Clouddal és a Kubernetes-el.)

Amint láttuk, több oka is lehet annak, hogy érdemes tesztelni az infrastruktúra kódját. Az egyik a hagyományos egységteszt. Mivel a kódnak lehetnek funkciók – például a CIDR kiszámítása, a nevek, címkék stb. dinamikus kiszámítása. - valószínűleg tesztelni szeretné őket. Ez ugyanaz, mintha rendszeres egységteszteket írna az alkalmazásokhoz kedvenc programozási nyelvén.
Egy kicsit bonyolultabbá tenni, ellenőrizheti, hogy a program hogyan allokálja az erőforrásokat. Szemléltetésképpen képzeljük el, hogy létre kell hoznunk egy egyszerű EC2 szervert, és biztosak akarunk lenni a következőkben:

  • A példányoknak van címkéje Name.
  • A példányok nem használhatnak inline szkriptet userData - AMI-t (image) kell használnunk.
  • Nem szabad, hogy SSH legyen kitéve az internetre.

Ez a példa azon alapul az én példám aws-js-webserver:

index.js:

"use strict";
 
let aws = require("@pulumi/aws");
 
let group = new aws.ec2.SecurityGroup("web-secgrp", {
    ingress: [
        { protocol: "tcp", fromPort: 22, toPort: 22, cidrBlocks: ["0.0.0.0/0"] },
        { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
    ],
});
 
let userData =
`#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &`;
 
let server = new aws.ec2.Instance("web-server-www", {
    instanceType: "t2.micro",
    securityGroups: [ group.name ], // reference the group object above
    ami: "ami-c55673a0"             // AMI for us-east-2 (Ohio),
    userData: userData              // start a simple web server
});
 
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;

Ez az alap Pulumi program: egyszerűen hozzárendel egy EC2 biztonsági csoportot és egy példányt. Meg kell azonban jegyezni, hogy itt mindhárom fent említett szabályt megszegjük. Írjunk teszteket!

Írásbeli tesztek

Tesztjeink általános felépítése úgy fog kinézni, mint a szokásos Mocha tesztek:

ec2tests.js

test.js:
let assert = require("assert");
let mocha = require("mocha");
let pulumi = require("@pulumi/pulumi");
let infra = require("./index");
 
describe("Infrastructure", function() {
    let server = infra.server;
    describe("#server", function() {
        // TODO(check 1): Должен быть тэг Name.
        // TODO(check 2): Не должно быть inline-скрипта userData.
    });
    let group = infra.group;
    describe("#group", function() {
        // TODO(check 3): Не должно быть SSH, открытого в Интернет.
    });
});

Most írjuk meg az első tesztünket: győződjön meg arról, hogy a példányokon van a címke Name. Ennek ellenőrzéséhez egyszerűen megkapjuk az EC2 példányobjektumot, és ellenőrizzük a megfelelő tulajdonságot tags:

 // check 1: Должен быть тэг Name.
        it("must have a name tag", function(done) {
            pulumi.all([server.urn, server.tags]).apply(([urn, tags]) => {
                if (!tags || !tags["Name"]) {
                    done(new Error(`Missing a name tag on server ${urn}`));
                } else {
                    done();
                }
            });
        });

Úgy néz ki, mint egy szokásos teszt, de néhány jellemzővel, amelyeket érdemes megjegyezni:

  • Mivel a telepítés előtt lekérdezzük egy erőforrás állapotát, tesztjeink mindig „terv” (vagy „előzetes”) módban futnak. Így sok olyan tulajdonság van, amelynek értékeit egyszerűen nem lehet lekérni, vagy nem lesz meghatározva. Ez magában foglalja a felhőszolgáltató által kiszámított összes kimeneti tulajdonságot. Ez normális tesztjeinknél – csak a bemeneti adatokat ellenőrizzük. Erre a kérdésre később még visszatérünk, amikor az integrációs tesztekről van szó.
  • Mivel az összes Pulumi erőforrás-tulajdonság kimenet, és sok közülük aszinkron módon kerül kiértékelésre, az értékek eléréséhez az apply metódust kell használnunk. Ez nagyon hasonlít az ígéretekhez és a funkcióhoz then .
  • Mivel több tulajdonságot használunk az erőforrás URN megjelenítésére a hibaüzenetben, a függvényt kell használnunk pulumi.allkombinálni őket.
  • Végül, mivel ezeket az értékeket aszinkron módon számítjuk ki, használnunk kell a Mocha beépített aszinkron visszahívási funkcióját. done vagy egy ígéret viszonzása.

Miután mindent beállítottunk, egyszerű JavaScript-értékként hozzáférhetünk a bemenetekhez. Ingatlan tags egy térkép (asszociatív tömb), ezért csak ellenőrizzük, hogy (1) nem hamis, és (2) van-e kulcs Name. Nagyon egyszerű, és most bármit kipróbálhatunk!

Most írjuk meg a második csekket. Még egyszerűbb:

 // check 2: Не должно быть inline-скрипта userData.
        it("must not use userData (use an AMI instead)", function(done) {
            pulumi.all([server.urn, server.userData]).apply(([urn, userData]) => {
                if (userData) {
                    done(new Error(`Illegal use of userData on server ${urn}`));
                } else {
                    done();
                }
            });
        });

És végül írjuk meg a harmadik tesztet. Ez egy kicsit bonyolultabb lesz, mert keressük a biztonsági csoporthoz tartozó bejelentkezési szabályokat, amelyekből sok lehet, és ezekben a szabályokban a CIDR tartományokat, amelyekből szintén sok lehet. De sikerült:

    // check 3: Не должно быть SSH, открытого в Интернет.
        it("must not open port 22 (SSH) to the Internet", function(done) {
            pulumi.all([ group.urn, group.ingress ]).apply(([ urn, ingress ]) => {
                if (ingress.find(rule =>
                        rule.fromPort == 22 && rule.cidrBlocks.find(block =>
                            block === "0.0.0.0/0"))) {
                    done(new Error(`Illegal SSH port 22 open to the Internet (CIDR 0.0.0.0/0) on group ${urn}`));
                } else {
                    done();
                }
            });
        });

Ez minden. Most pedig futtassuk le a teszteket!

Tesztek futtatása

A legtöbb esetben a szokásos módon, az Ön által választott tesztkeret segítségével futtathatja a teszteket. De a Puluminak van egy olyan tulajdonsága, amire érdemes odafigyelni.
A Pulumi programok futtatásához jellemzően a pulimi CLI-t (Command Line interface) használják, amely konfigurálja a nyelvi futásidőt, vezérli a Pulumi motor indítását, hogy az erőforrásokkal végzett műveletek rögzíthetők és a tervben szerepelhessenek stb. Van azonban egy probléma. Ha a tesztkeretrendszer felügyelete alatt fut, nem lesz kommunikáció a CLI és a Pulumi motor között.

A probléma megkerüléséhez csak a következőket kell megadnunk:

  • Projektnév, amely a környezeti változóban található PULUMI_NODEJS_PROJECT (vagy általánosabban, PULUMI__PROJECT для других языков).
    A környezeti változóban megadott verem neve PULUMI_NODEJS_STACK (vagy általánosabban, PULUMI__ STACK).
    A verem konfigurációs változói. Ezeket egy környezeti változó segítségével lehet megszerezni PULUMI_CONFIG formátumuk pedig JSON-leképezés kulcs/érték párokkal.

    A program figyelmeztetéseket ad ki, jelezve, hogy a kapcsolat a CLI-vel/motorral nem érhető el a végrehajtás során. Ez azért fontos, mert a program valójában nem telepít semmit, és meglepő lehet, ha nem ezt tervezte! Telepítheti, hogy elmondja a Puluminak, hogy pontosan erre van szüksége PULUMI_TEST_MODE в true.

    Képzeld el, hogy meg kell adnunk a projekt nevét my-ws, verem neve devés AWS régió us-west-2. A Mocha tesztek futtatásának parancssora így fog kinézni:

    $ PULUMI_TEST_MODE=true 
        PULUMI_NODEJS_STACK="my-ws" 
        PULUMI_NODEJS_PROJECT="dev" 
        PULUMI_CONFIG='{ "aws:region": "us-west-2" }' 
        mocha tests.js

    Ha ezt a várakozásoknak megfelelően megtesszük, megmutatjuk, hogy három sikertelen tesztünk van!

    Infrastructure
        #server
          1) must have a name tag
     	 2) must not use userData (use an AMI instead)
        #group
          3) must not open port 22 (SSH) to the Internet
    
      0 passing (17ms)
      3 failing
     
     1) Infrastructure
           #server
             must have a name tag:
         Error: Missing a name tag on server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     2) Infrastructure
           #server
             must not use userData (use an AMI instead):
         Error: Illegal use of userData on server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     3) Infrastructure
           #group
             must not open port 22 (SSH) to the Internet:
         Error: Illegal SSH port 22 open to the Internet (CIDR 0.0.0.0/0) on group

    Javítsuk ki a programunkat:

    "use strict";
     
    let aws = require("@pulumi/aws");
     
    let group = new aws.ec2.SecurityGroup("web-secgrp", {
        ingress: [
            { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
        ],
    });
     
    let server = new aws.ec2.Instance("web-server-www", {
        tags: { "Name": "web-server-www" },
        instanceType: "t2.micro",
        securityGroups: [ group.name ], // reference the group object above
        ami: "ami-c55673a0"             // AMI for us-east-2 (Ohio),
    });
     
    exports.group = group;
    exports.server = server;
    exports.publicIp = server.publicIp;
    exports.publicHostName = server.publicDns;
    

    Ezután futtassa újra a teszteket:

    Infrastructure
        #server
          ✓ must have a name tag
          ✓ must not use userData (use an AMI instead)
        #group
          ✓ must not open port 22 (SSH) to the Internet
     
     
     3 passing (16ms)

    Minden jól ment... Hurrá! ✓✓✓

    Mára ennyi, de a telepítési tesztelésről a fordítás második részében lesz szó 😉

Forrás: will.com

Hozzászólás