Testning av infrastruktur som kod med Pulumi. Del 1

God dag, vÀnner. I förberedelse inför starten av den nya omgÄngen av kursen «DevOps metoder och verktyg» delar vi med er en ny översÀttning. LÄt oss börja.

Testning av infrastruktur som kod med Pulumi. Del 1

Att anvĂ€nda Pulumi och allmĂ€ngiltiga programmeringssprĂ„k för infrastrukturkod (Infrastructure as Code) ger mĂ„nga fördelar: tillgĂ„ng till fĂ€rdigheter och kunskaper, eliminering av boilerplate-kod genom abstraktion, verktyg som din team Ă€r bekanta med, sĂ„som IDE:er och linters. Alla dessa programvaruingenjörsverktyg gör oss inte bara mer produktiva, utan förbĂ€ttrar Ă€ven kodens kvalitet. DĂ€rför Ă€r det helt naturligt att anvĂ€nda allmĂ€ngiltiga programmeringssprĂ„k för att införa ytterligare en viktig programvaruutvecklingspraxis — testning.

I denna artikel kommer vi att se hur Pulumi hjÀlper oss att testa vÄr "infrastruktur som kod".

Testning av infrastruktur som kod med Pulumi. Del 1

Varför testa infrastruktur?

Innan vi gÄr in pÄ detaljerna Àr det vÀrt att stÀlla frÄgan: "Varför ska vi ens testa infrastruktur?" Det finns mÄnga anledningar till detta, och hÀr Àr nÄgra av dem:

  • Enhetstestning av enskilda funktioner eller fragment av logiken i ditt program
  • Kontroll av det önskade tillstĂ„ndet för infrastrukturen i förhĂ„llande till vissa begrĂ€nsningar.
  • UpptĂ€ckte vanliga fel, som brist pĂ„ kryptering av lagringsbucket eller oskyddad, öppen Ă„tkomst frĂ„n Internet till virtuella maskiner.
  • Verifiera att provisioneringen av infrastrukturen genomförs.
  • Genomföra runtime-testning av applikationslogik som körs inom din "programmerade" infrastruktur för att sĂ€kerstĂ€lla funktionalitet efter provisionering.
  • Som vi ser finns det ett brett spektrum av metoder för att testa infrastruktur. Pulumi har mekanismer för att testa vid varje punkt i detta spektrum. LĂ„t oss börja och se hur det fungerar.

Enhetstestning

Pulumi-program skapas med allmÀngiltiga programmeringssprÄk som JavaScript, Python, TypeScript eller Go. DÀrför har de tillgÄng till hela kraften i dessa sprÄk, inklusive deras verktyg och bibliotek, inklusive test-ramverk. Pulumi Àr multisky, vilket innebÀr att det kan anvÀnda alla molnleverantörer för tester.

(I denna artikel, trots flersprÄkighet och multi-moln, anvÀnder vi JavaScript och Mocha och fokuserar pÄ AWS. Det gÄr att anvÀnda Python unittest, test-ramverket Go eller vilket annat test-ramverk du föredrar. Och givetvis fungerar Pulumi utmÀrkt med Azure, Google Cloud, Kubernetes.)

Som vi har sett finns det flera anledningar till att testa din infrastrukturkod. En av dem Ă€r vanlig modulĂ€r testning. Eftersom din kod kan ha funktioner — till exempel för att berĂ€kna CIDR, dynamisk berĂ€kning av namn, etiketter, etc. — vill du sannolikt testa dem. Det Ă€r densamma som att skriva vanliga modulĂ€ra tester för program i ditt favoritprogrammeringssprĂ„k.
Om vi gör det lite mer komplext kan vi kontrollera hur ditt program fördelar resurser. För att illustrera, lÄt oss tÀnka oss att vi behöver skapa en enkel EC2-server och vi vill sÀkerstÀlla följande:

  • Instanserna har en etikett Namn.
  • Instanser fĂ„r inte anvĂ€nda inline-skript userData — vi mĂ„ste anvĂ€nda AMI (avbild).
  • Det fĂ„r inte finnas SSH öppet mot Internet.

Detta exempel Àr inspirerat av mitt exempel 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 ], // referera till gruppobjektet ovan
    ami: "ami-c55673a0"             // AMI för us-east-2 (Ohio),
    userData: userData              // starta en enkel webbserver
});
 
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;

Detta Àr det grundlÀggande Pulumi-programmet: det allokerar helt enkelt en sÀkerhetsgrupp för EC2 och en instans. Men det Àr vÀrt att notera att vi hÀr bryter mot alla tre reglerna som anges ovan. LÄt oss skriva tester!

Skriv tester

Den allmÀnna strukturen för vÄra tester kommer att se ut som vanliga Mocha-tester:

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): Det ska finnas en Name-etikett.
        // TODO(check 2): Det ska inte finnas nÄgot inline-skript userData.
    });
    let group = infra.group;
    describe("#group", function() {
        // TODO(check 3): Det ska inte finnas SSH öppet mot Internet.
    });
});

LÄt oss nu skriva vÄrt första test: vi ska sÀkerstÀlla att instanserna har en tagg Namn. För att kontrollera detta hÀmtar vi helt enkelt ett EC2-instanser och kontrollerar den relevanta egenskapen 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();
                }
            });
        });

Det ser ut som ett vanligt test, men med nÄgra aspekter som Àr vÀrda att notera:

  • Eftersom vi begĂ€r resursens tillstĂ„nd innan utrullning, körs vĂ„ra tester alltid i "plan" (eller "preview"). DĂ€rför finns det mĂ„nga egenskaper vars vĂ€rden helt enkelt inte kommer att hĂ€mtas eller kommer att vara odefinierade. Detta inkluderas i alla utdataegenskaper som berĂ€knas av din molnleverantör. För vĂ„ra tester Ă€r detta okej – vi kontrollerar bara indata. Vi kommer att Ă„terkomma till detta senare nĂ€r det gĂ€ller integrationstester.
  • Eftersom alla Pulumi-resursegenskaper Ă€r "utgĂ„ngar", och mĂ„nga av dem berĂ€knas asynkront, mĂ„ste vi anvĂ€nda metoden apply för att komma Ă„t vĂ€rdena. Det liknar mycket löften och en funktionsmetod then .
  • Eftersom vi anvĂ€nder flera egenskaper för att visa resursens URN i felmeddelandet, behöver vi anvĂ€nda funktionen pulumi.all, för att kombinera dem.
  • Slutligen, eftersom dessa vĂ€rden berĂ€knas asynkront, mĂ„ste vi anvĂ€nda den inbyggda asynkrona funktionen frĂ„n Mocha med ett callback done eller genom att returnera ett löfte.

NÀr vi har stÀllt in allt, kommer vi att ha tillgÄng till indata som enkla JavaScript-vÀrden. Egenskapen tags Àr en karta (associativ array), sÄ vi ser helt enkelt till att det (1) inte Àr false, och (2) finns en nyckel för Namn. Detta Àr mycket enkelt och nu kan vi kontrollera vad som helst!

Nu lÄt oss skriva vÄr andra kontroll. Detta Àr Ànnu enklare:

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

Och slutligen, lÄt oss skriva det tredje testet. Detta kommer att vara lite svÄrare, eftersom vi letar efter in- och utregler kopplade till sÀkerhetsgruppen, som kan vara mÄnga, och CIDR-intervall i dessa regler, som ocksÄ kan vara mÄnga. Men vi klarade det:

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

Det Àr allt. LÄt oss nu köra testerna!

Kör tester

Att köra tester gÄr i de flesta fall att göra pÄ vanligt sÀtt, med hjÀlp av den testram som du valt. Men det finns en egenskap hos Pulumi som Àr vÀrt att notera.
Vanligtvis anvÀnds pulimi CLI (Command Line Interface, kommandoradsgrÀnssnitt) för att köra Pulumi-program, som konfigurerar sprÄkets runtime, kontrollerar körningarna av Pulumi-motorn för att registrera ÄtgÀrder med resurser och inkludera dem i planen osv. Men det finns ett problem. NÀr du kör under övervakning av ditt testframework kommer det inte att finnas nÄgon koppling mellan CLI och Pulumi-motorn.

För att kringgÄ detta problem behöver vi helt enkelt ange följande:

  • Projektets namn, vilket finns i miljövariabeln PULUMI_NODEJS_PROJECT (eller mer allmĂ€nt, PULUMI__PROJECT för andra sprĂ„k).
    Namn pÄ stacken, vilket anges i miljövariabeln PULUMI_NODEJS_STACK (eller mer allmÀnt, PULUMI__STACK).
    Dina konfigurationsvariabler för stacken. Dessa kan erhÄllas med hjÀlp av miljövariabeln PULUMI_CONFIG och deras format Àr en JSON-karta med nyckel/vÀrde-par.

    Programmet kommer att ge varningar som sÀger att det under körning inte finns nÄgon anslutning till CLI/motorn. Detta Àr viktigt, eftersom din program i sjÀlva verket inte kommer att distribuera nÄgot, och det kan bli en överraskning om det inte var vad du ville göra! För att sÀga till Pulumi att detta Àr exakt vad du behöver kan du stÀlla in PULUMI_TEST_MODE pÄ true.

    TÀnk dig att vi behöver ange namnet pÄ projektet som my-ws, namnet pÄ stacken dev, och AWS-regionen us-west-2. Kommandoraden för att köra Mocha-testerna ser ut sÄ hÀr:

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

    Att köra detta, som förvÀntat, visar oss att vi har tre misslyckade tester!

    Infrastruktur
        #server
          1) mÄste ha en namnetikett
     	 2) fÄr inte anvÀnda userData (anvÀnd en AMI istÀllet)
        #grupp
          3) fÄr inte öppna port 22 (SSH) för Internet
    
      0 passerar (17ms)
      3 misslyckas
     
     1) Infrastruktur
           #server
             mÄste ha en namnetikett:
         Fel: Saknar en namnetikett för server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     2) Infrastruktur
           #server
             fÄr inte anvÀnda userData (anvÀnd en AMI istÀllet):
         Fel: OtillÄten anvÀndning av userData pÄ server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     3) Infrastruktur
           #grupp
             fÄr inte öppna port 22 (SSH) för Internet:
         Fel: OtillÄten SSH-port 22 öppen för Internet (CIDR 0.0.0.0/0) pÄ gruppen

    LÄt oss fixa vÄrt program:

    "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 ], // referera till gruppobjektet ovan
        ami: "ami-c55673a0"             // AMI för us-east-2 (Ohio),
    });
     
    exports.group = group;
    exports.server = server;
    exports.publicIp = server.publicIp;
    exports.publicHostName = server.publicDns;
    

    Och sedan kör vi testerna igen:

    Infrastruktur
        #server
          ✓ mĂ„ste ha en namnetikett
          ✓ fĂ„r inte anvĂ€nda userData (anvĂ€nd en AMI istĂ€llet)
        #grupp
          ✓ fĂ„r inte öppna port 22 (SSH) för Internet
     
     
     3 godkÀnda (16ms)

    Allt gick bra
 Hurrra! ✓✓✓

    Det var allt för idag, vi pratar om testning av distributionen i den andra delen av översĂ€ttningen 😉

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster