Ynfrastruktuer testen as koade mei Pulumi. Diel 1

Goeiemiddei freonen. Yn ôfwachting fan it begjin fan in nije stream op it taryf "DevOps-praktiken en ark" Wy diele in nije oersetting mei jo. Gean.

Ynfrastruktuer testen as koade mei Pulumi. Diel 1

It brûken fan Pulumi en programmeartalen foar algemiene doelen foar ynfrastruktuerkoade (Infrastructure as Code) biedt in protte foardielen: de beskikberens fan feardigens en kennis, eliminaasje fan boilerplate yn 'e koade troch abstraksje, ark bekend foar jo team, lykas IDE's en linters. Al dizze ark foar software-engineering meitsje ús net allinich produktiver, mar ferbetterje ek de kwaliteit fan ús koade. Dêrom is it allinich natuerlik dat it gebrûk fan programmeartalen foar algemiene doelen ús in oare wichtige softwareûntwikkelingpraktyk yntrodusearje kinne - testen.

Yn dit artikel sille wy sjen hoe't Pulumi ús helpt ús ynfrastruktuer-as-koade te testen.

Ynfrastruktuer testen as koade mei Pulumi. Diel 1

Wêrom testen ynfrastruktuer?

Foardat jo yn detail geane, is it de muoite wurdich de fraach te stellen: "Wêrom ynfrastruktuer überhaupt testen?" D'r binne in protte redenen foar dit en hjir binne guon fan harren:

  • Ienheidstesten fan yndividuele funksjes as fragminten fan jo programmalogika
  • Ferifiearret de winske steat fan 'e ynfrastruktuer tsjin bepaalde beheiningen.
  • Deteksje fan mienskiplike flaters, lykas in gebrek oan fersifering fan in opslachbak of ûnbeskerme, iepen tagong fan it ynternet nei firtuele masines.
  • Kontrolearje de ymplemintaasje fan ynfrastruktuerfoarsjenning.
  • Runtime-testen útfiere fan applikaasjelogika dy't rint yn jo "programmeare" ynfrastruktuer om funksjonaliteit te kontrolearjen nei foarsjenning.
  • Lykas wy kinne sjen, is d'r in breed oanbod fan opsjes foar ynfrastruktuertesten. Polumi hat meganismen foar testen op elk punt op dit spektrum. Litte wy begjinne en sjen hoe't it wurket.

Unit testen

Pulumi-programma's binne skreaun yn programmeartalen foar algemiene doelen lykas JavaScript, Python, TypeScript of Go. Dêrom is de folsleine krêft fan dizze talen, ynklusyf har ark en bibleteken, ynklusyf testkaders, foar har beskikber. Pulumi is multi-cloud, wat betsjut dat it kin wurde brûkt foar testen fan elke wolkprovider.

(Yn dit artikel brûke wy, nettsjinsteande meartaligens en multicloud, JavaScript en Mocha en rjochtsje wy ús op AWS. Jo kinne Python brûke unittest, Gean testkader, of in oar testkader dat jo wolle. En, fansels, Pulumi wurket geweldich mei Azure, Google Cloud, Kubernetes.)

Lykas wy hawwe sjoen, binne d'r ferskate redenen wêrom't jo jo ynfrastruktuerkoade miskien wolle testen. Ien fan harren is konvinsjonele ienheid testen. Om't jo koade funksjes hawwe kin - bygelyks om CIDR te berekkenjen, dynamysk berekkenje nammen, tags, ensfh. - jo sille se wierskynlik wolle testen. Dit is itselde as it skriuwen fan reguliere ienheidstests foar applikaasjes yn jo favorite programmeartaal.
Om in bytsje komplisearre te wurden, kinne jo kontrolearje hoe't jo programma boarnen allocearret. Om te yllustrearjen, litte wy ús foarstelle dat wy in ienfâldige EC2-tsjinner moatte oanmeitsje en wy wolle wis wêze fan it folgjende:

  • Ynstânsjes hawwe in tag Name.
  • Ynstânsjes moatte gjin inline skript brûke userData - wy moatte in AMI (ôfbylding) brûke.
  • D'r soe gjin SSH wêze moatte bleatsteld oan it ynternet.

Dit foarbyld is basearre op myn foarbyld 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;

Dit is it basisprogramma fan Pulumi: it jout gewoan in EC2-befeiligingsgroep en in eksimplaar ta. It moat lykwols opmurken wurde dat wy hjir alle trije hjirboppe neamde regels brekke. Litte wy tests skriuwe!

Skriuwen tests

De algemiene struktuer fan ús tests sil lykje op reguliere Mocha-tests:

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, открытого в Интернет.
    });
});

Litte wy no ús earste test skriuwe: soargje derfoar dat de eksimplaren de tag hawwe Name. Om dit te kontrolearjen krije wy gewoan it EC2-eksimplaarobjekt en kontrolearje de oerienkommende eigenskip 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();
                }
            });
        });

It liket op in gewoane test, mar mei in pear funksjes dy't opmerklik binne:

  • Om't wy de steat fan in boarne opfreegje foar ynset, wurde ús tests altyd útfierd yn "plan" (of "foarbyld") modus. Sa binne d'r in protte eigenskippen wêrfan de wearden gewoan net sille wurde ophelle of net sille wurde definieare. Dit omfettet alle útfiereigenskippen berekkene troch jo wolkprovider. Dit is normaal foar ús tests - wy kontrolearje allinich de ynfiergegevens. Wy komme letter op dizze kwestje werom, as it giet om yntegraasjetests.
  • Sûnt alle Pulumi-boarne-eigenskippen binne útgongen, en in protte fan harren wurde asynchronously evaluearre, wy moatte brûke de applikaasje metoade foar tagong ta de wearden. Dit is heul gelyk oan beloften en afunksje then .
  • Om't wy ferskate eigenskippen brûke om de boarne URN yn it flaterberjocht te sjen, moatte wy de funksje brûke pulumi.allom se te kombinearjen.
  • Uteinlik, om't dizze wearden asynchronysk wurde berekkene, moatte wy Mocha's ynboude asyngroane werombelfunksje brûke done of werom in belofte.

Sadree't wy hawwe ynsteld alles, wy hawwe tagong ta de yngongen as ienfâldige JavaScript wearden. Besit tags is in kaart (assosjatyf array), dus wy sille gewoan soargje dat it (1) net falsk is, en (2) d'r in kaai is foar Name. It is heul ienfâldich en no kinne wy ​​alles testen!

Litte wy no ús twadde kontrôle skriuwe. It is noch ienfâldiger:

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

En as lêste, litte wy de tredde test skriuwe. Dit sil in bytsje yngewikkelder wêze, om't wy sykje nei de oanmeldregels dy't ferbûn binne mei de feiligensgroep, wêrfan d'r in protte kinne wêze, en de CIDR-beriken yn dy regels, wêrfan d'r ek in protte kinne wêze. Mar it slagge ús:

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

Da's alles. No litte wy de tests útfiere!

Running tests

Yn 'e measte gefallen kinne jo testen op' e gewoane manier útfiere, mei it testkader fan jo kar. Mar d'r is ien skaaimerk fan Pulumi dat it wurdich is om omtinken te jaan.
Typysk, om Pulumi-programma's út te fieren, wurdt de pulimi CLI (Command Line-ynterface) brûkt, dy't de taalruntime konfigurearret, de lansearring fan 'e Pulumi-motor kontrolearret, sadat operaasjes mei boarnen kinne wurde opnommen en opnommen yn it plan, ensfh. D'r is lykwols ien probleem. As jo ​​rinne ûnder de kontrôle fan jo testkader, sil d'r gjin kommunikaasje wêze tusken de CLI en de Pulumi-motor.

Om dit probleem om te kommen, moatte wy gewoan it folgjende spesifisearje:

  • Projektnamme, dy't befette is yn 'e omjouwingsfariabele PULUMI_NODEJS_PROJECT (of, mear algemien, PULUMI__PROJECT для других языков).
    De namme fan de stack dy't is oantsjutte yn de omjouwingsfariabele PULUMI_NODEJS_STACK (of, mear algemien, PULUMI__ STACK).
    Jo stack konfiguraasje fariabelen. Se kinne wurde krigen mei in omjouwingsfariabele PULUMI_CONFIG en harren opmaak is JSON map mei kaai / wearde pearen.

    It programma sil warskôgingen útjaan dy't oanjaan dat de ferbining mei de CLI / motor net beskikber is tidens útfiering. Dit is wichtich om't jo programma eins neat sil ynsette en it kin as in ferrassing komme as dat net is wat jo fan doel hawwe te dwaan! Om Pulumi te fertellen dat dit krekt is wat jo nedich binne, kinne jo ynstallearje PULUMI_TEST_MODE в true.

    Stel jo foar dat wy de projektnamme yn moatte opjaan my-ws, stack namme dev, en AWS-regio us-west-2. De kommandorigel foar it útfieren fan Mocha-tests sil der sa útsjen:

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

    Dit dwaan, lykas ferwachte, sil ús sjen litte dat wy trije mislearre tests hawwe!

    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

    Litte wy ús programma reparearje:

    "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;
    

    En dan wer de tests útfiere:

    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)

    Alles gie goed... Hoera! ✓✓✓

    Dat is alles foar hjoed, mar wy sille prate oer ynset testen yn it twadde diel fan 'e oersetting 😉

Boarne: www.habr.com

Add a comment