Testovanie infraštruktúry ako kódu pomocou Pulumi. Časť 1

Dobrý deň, priatelia. V očakávaní začiatku nového cyklu kurzu „Praktiky a nástroje DevOps“ sa s vami delíme o nový preklad. Poďme na to.

Testovanie infraštruktúry ako kódu pomocou Pulumi. Časť 1

Použitie Pulumi a jazykov programovania vysokého poradia na infraštruktúrny kód (Infrastructure as Code) prináša množstvo výhod: existujúce zručnosti a vedomosti, eliminácia boilerplate kódu prostredníctvom abstrakcie a známe nástroje vašim tímom ako IDE a lintery. Všetky tieto nástroje softvérového inžinierstva nás nielenže robia produktívnejšími, ale tiež zlepšujú kvalitu kódu. Preto je úplne prirodzené, že používanie jazykov programovania vysokého poradia umožňuje zaviesť ďalšiu dôležitú prax vývoja softvéru — testovanie.

V tomto článku sa pozrieme na to, ako Pulumi pomáha testovať našu „infrastruktúru ako kód“.

Testovanie infraštruktúry ako kódu pomocou Pulumi. Časť 1

Prečo testovať infraštruktúru?

Predtým, ako sa pustíme do detailov, stojí za to položiť otázku: „Prečo vôbec testovať infraštruktúru?“ Existuje mnoho dôvodov a tu je niekoľko z nich:

  • Modulárne testovanie jednotlivých funkcií alebo fragmentov logiky vášho programu
  • Overenie želaného stavu infraštruktúry v súlade s definovanými obmedzeniami.
  • Zistenie bežných chýb, ako je absencia šifrovania storage bucket alebo nezabezpečený, otvorený prístup z internetu k virtuálnym strojom.
  • Overenie vykonania provisioning infraštruktúry.
  • Vykonanie runtime testovania logiky aplikácie bežiacej v rámci vašej „naprogramovanej“ infraštruktúry na overenie funkčnosti po provisioning.
  • Ako vidíme, existuje široké spektrum možností testovania infraštruktúry. V Pulumi existujú mechanizmy na testovanie v každom bode tohto spektra. Poďme začať a pozrime sa, ako to funguje.

Modulárne testovanie

Pulumi programy sú vytvárané v jazykoch programovania vysokého poradia ako JavaScript, Python, TypeScript alebo Go. Preto je k dispozícii plná moc týchto jazykov, vrátane ich nástrojov a knižníc, vrátane testovacích rámcov. Pulumi je viaccloudový, čo znamená, že môžete na testy použiť akýchkoľvek poskytovateľov cloudových služieb.

(V tomto článku, napriek multijazyčnosti a viaccloudovému prístupu, používame JavaScript a Mocha a zameriavame sa na AWS. Je možné použiť Python unittest, testovací rámec Go alebo akýkoľvek iný obľúbený testovací rámec. A samozrejme, Pulumi skvele funguje s Azure, Google Cloud, Kubernetes.)

Ako sme videli, existuje niekoľko dôvodov, prečo môže byť potrebné testovať váš infraštrukturný kód. Jedným z nich je bežné modulárne testovanie. Keďže váš kód môže mať funkcie – napríklad na výpočet CIDR, dynamické vytváranie mien, tagov atď. – pravdepodobne ich budete chcieť otestovať. Je to to isté ako napísať bežné modulárne testy pre aplikácie vo vašom obľúbenom programovacom jazyku.
Ak trochu skomplikujeme, môžeme overiť, ako vaša aplikácia rozdeľuje zdroje. Na ilustráciu si predstavme, že potrebujeme vytvoriť jednoduchý EC2 server a chceme si byť istí nasledujúcim:

  • Inštancie majú tag Názov.
  • Inštancie by nemali používať inline skript userData – musíme použiť AMI (obraz).
  • Nemalo by byť povolené SSH otvorené na internete.

Tento príklad je založený na mojom príklade 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 ], \/\/ referencujte objekt skupiny vyššie
    ami: "ami-c55673a0" 	     \/\/ AMI pre us-east-2 (Ohio),
    userData: userData 	     \/\/ spustiť jednoduchý webový server
});
 
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;

Toto je základný program Pulumi: jednoducho alokuje skupinu zabezpečenia EC2 a inštanciu. Je však potrebné poznamenať, že tu porušujeme všetky tri pravidlá uvedené vyššie. Poďme písať testy!

Píšeme testy

Celková štruktúra našich testov bude vyzerať ako bežné Mocha testy:

ec2tests.js

test.js:
let assert = require("assert");
let mocha = require("mocha");
let pulumi = require("@pulumi/pulumi");
let infra = require("./index");
 
describe("Infraštruktúra", function() {
    let server = infra.server;
    describe("#server", function() {
        \/\/ TODO(check 1): Mal by mať tag Name.
        \/\/ TODO(check 2): Nemal by byť inline skript userData.
    });
    let group = infra.group;
    describe("#group", function() {
        \/\/ TODO(check 3): Nemalo by byť povolené SSH otvorené na internete.
    });
});

Teraz poďme napísať našu prvú testovaciu jednotku: uistime sa, že inštancie majú tag Názov. Na overenie toho jednoducho získame objekt EC2 inštancie a skontrolujeme príslušnú vlastnosť 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();
                }
            });
        });

Vyzerá to ako bežný test, ale s niekoľkými významnými vlastnosťami, ktoré si zaslúžia pozornosť:

  • Keďže pred nasadením kontrolujeme stav zdroja, naše testy sa vždy vykonávajú v režime "plan" (alebo "preview"). Takže existuje veľa vlastností, ktorých hodnoty jednoducho nebudú získať alebo budú nedefinované. Sem patrí všetko výstupné vlastnosti, ktoré vypočítava váš cloudový poskytovateľ. Pre naše testy je to v poriadku — kontrolujeme iba vstupné údaje. K tejto otázke sa ešte vrátime neskôr, keď sa dostaneme k integračným testom.
  • Keďže všetky vlastnosti Pulumi-zdrojov sú "výstupy", a mnohé z nich sú vypočítavané asynchrónne, musíme použiť metódu apply, aby sme získali prístup k hodnotám. To je veľmi podobné promesom a afunkcii. then .
  • Keďže používame niekoľko vlastností na zobrazenie URN zdroja v chybovej hláške, musíme použiť funkciu pulumi.all, aby sme ich spojili.
  • Nakoniec, keďže tieto hodnoty sa vypočítavajú asynchrónne, musíme využiť vstavanú asynchrónnu funkciu Mocha s spätným volaním done alebo vrátením promesu.

Po tom, čo všetko nastavíme, budeme mať prístup k vstupným údajom ako k jednoduchým hodnotám JavaScriptu. Vlastnosť tags je map (asociatívny pód), takže sa len uistíme, že je (1) nie false, a (2) existuje kľúč pre Názov. Je to veľmi jednoduché a teraz môžeme skontrolovať čokoľvek!

Teraz napíšme našu druhú kontrolu. To je ešte jednoduchšie:

 // 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();
                }
            });
        });

A nakoniec napíšme tretí test. Bude to trochu zložitejšie, pretože hľadáme pravidlá vstupu súvisiace s bezpečnostnou skupinou, ktorých môže byť veľa, a rozsahy CIDR v týchto pravidlách, ktorých môže byť tiež veľa. Ale zvládli sme to:

    // 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();
                }
            });
        });

A je to. Teraz spustíme testy!

Spustenie testov

Testy sa vo väčšine prípadov dajú spustiť bežným spôsobom, pomocou vami vybraného testovacieho rámca. Ale existuje jedna zvláštnosť Pulumi, na ktorú si treba dať pozor.
Na spustenie Pulumi programov sa zvyčajne používa pulimi CLI (Command Line interface, rozhranie príkazového riadka), ktoré nastavuje runtime jazyka, ovláda spustenie Pulumi enginu, aby sa dali zaznamenávať operácie s prostriedkami a zahrnúť ich do plánu atď. Avšak existuje jeden problém. Pri spustení pod kontrolou vašej testovacej frameworku nebude žiadne prepojenie medzi CLI a Pulumi enginom.

Aby sme sa vyhli tomuto problému, musíme jednoducho zadať nasledujúce:

  • Názov projektu, ktorý je obsiahnutý v premennej prostredia PULUMI_NODEJS_PROJECT (alebo, v všeobecnejších prípadoch, PULUMI__PROJECT pre iné jazyky).
    Názov stacku, ktorý je uvedený v premennej prostredia PULUMI_NODEJS_STACK (alebo, v všeobecnejších prípadoch, PULUMI__STACK).
    Vaše premenné konfigurácie stacku. Môžu byť získané pomocou premennej prostredia PULUMI_CONFIG a ich formát predstavuje JSON map s pármi kľúč/hodnota.

    Program vydá upozornenia, ktoré hovoria, že počas vykonávania nie je dostupné spojenie s CLI/enginom. Je to dôležité, pretože v skutočnosti vaša aplikácia nič nerozmiestňuje a to môže byť prekvapením, ak to nie je to, čo ste chceli urobiť! Aby ste povedali Pulumi, že toto je presne to, čo potrebujete, môžete nastaviť PULUMI_TEST_MODE v true.

    Predstavte si, že potrebujeme zadať názov projektu v my-ws, názov stacku dev, a región AWS us-west-2. Príkazový riadok na vykonanie Mocha testov bude vyzerať nasledovne:

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

    Vykonanie tohto, ako sa očakávalo, nám ukáže, že máme tri zlyhané testy!

    Infrastructure
        #server
          1) musí mať názov tagu
     	 2) nesmie používať userData (použite radšej AMI)
        #group
          3) nesmie otvárať port 22 (SSH) na Internet
    
      0 úspešných (17ms)
      3 zlyhali
     
     1) Infrastructure
           #server
             musí mať názov tagu:
         Error: Chýba názov tagu na serveri
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     2) Infrastructure
           #server
             nesmie používať userData (použite radšej AMI):
         Error: Nelegálne používanie userData na serveri
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     3) Infrastructure
           #group
             nesmie otvárať port 22 (SSH) na Internet:
         Error: Nelegálne otvorený SSH port 22 na Internet (CIDR 0.0.0.0/0) na skupine

    Opraveníme našu aplikáciu:

    "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 pre us-east-2 (Ohio),
    });
     
    exports.group = group;
    exports.server = server;
    exports.publicIp = server.publicIp;
    exports.publicHostName = server.publicDns;
    

    A potom znovu spustíme testy:

    Infraštruktúra
        #server
          ✓ musí mať meno tagu
          ✓ nesmie používať userData (namiesto toho použite AMI)
        #group
          ✓ nesmie otvárať port 22 (SSH) na internete
     
     
     3 prechody (16ms)

    Všetko prebehlo úspešne… Hurá! ✓✓✓

    Na dnes je to všetko, o testovaní nasadenia sa porozprávame v druhej časti prekladu 😉

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster