Infrastruktuuri testimine koodina Pulumiga. 1. osa

Tere päevast sõbrad. Uue voolu alguse ootuses kiirusega "DevOpsi tavad ja tööriistad" Jagame teiega uut tõlget. Mine.

Infrastruktuuri testimine koodina Pulumiga. 1. osa

Pulumi ja üldotstarbeliste programmeerimiskeelte kasutamine infrastruktuuri koodis (Infrastructure as Code) annab palju eeliseid: oskuste ja teadmiste olemasolu, koodis sisalduva plaadi eemaldamine abstraktsiooni kaudu, teie meeskonnale tuttavad tööriistad, nagu IDE-d ja linterid. Kõik need tarkvaratehnoloogia tööriistad mitte ainult ei muuda meid tootlikumaks, vaid parandavad ka meie koodi kvaliteeti. Seetõttu on täiesti loomulik, et üldotstarbeliste programmeerimiskeelte kasutamine võimaldab meil tutvustada veel ühte olulist tarkvaraarenduse tava - kontrollimine.

Selles artiklis vaatleme, kuidas Pulumi aitab meil testida meie infrastruktuuri koodina.

Infrastruktuuri testimine koodina Pulumiga. 1. osa

Miks testida infrastruktuuri?

Enne detailidesse laskumist tasub küsida: "Milleks üldse infrastruktuuri testida?" Sellel on palju põhjuseid ja siin on mõned neist:

  • Üksikute funktsioonide või teie programmiloogika fragmentide testimine
  • Kontrollib infrastruktuuri soovitud olekut teatud piiranguteta.
  • Tavaliste vigade tuvastamine, näiteks salvestusruumi krüptimise puudumine või kaitsmata avatud juurdepääs Internetist virtuaalsetele masinatele.
  • Infrastruktuuri pakkumise rakendamise kontrollimine.
  • Teie "programmeeritud" infrastruktuuri sees töötava rakenduseloogika käitusaja testimine, et kontrollida funktsionaalsust pärast ettevalmistamist.
  • Nagu näeme, on infrastruktuuri testimise võimalusi lai valik. Polumil on mehhanismid testimiseks selle spektri igas punktis. Alustame ja vaatame, kuidas see töötab.

Ühiku testimine

Pulumi programmid on kirjutatud üldotstarbelistes programmeerimiskeeltes, nagu JavaScript, Python, TypeScript või Go. Seetõttu on neile kättesaadav nende keelte kogu võimsus, sealhulgas nende tööriistad ja teegid, sealhulgas testraamistikud. Pulumi on multipilv, mis tähendab, et seda saab testimiseks kasutada iga pilveteenuse pakkuja juures.

(Hoolimata sellest, et see on mitmekeelne ja multicloud, kasutame selles artiklis JavaScripti ja Mochat ning keskendume AWS-ile. Võite kasutada Pythonit unittest, Go testraamistik või mõni muu testraamistik, mis teile meeldib. Ja loomulikult töötab Pulumi suurepäraselt koos Azure'i, Google Cloudi ja Kubernetesega.)

Nagu nägime, on mitu põhjust, miks võiksite oma infrastruktuuri koodi testida. Üks neist on tavapärane ühikutestimine. Kuna teie koodil võib olla funktsioone – näiteks CIDR-i arvutamiseks, nimede, siltide jms dünaamiliseks arvutamiseks. - tõenäoliselt soovite neid testida. See on sama, mis tavaliste ühiktestide kirjutamine rakenduste jaoks oma lemmikprogrammeerimiskeeles.
Veidi keerulisemaks muutmiseks saate kontrollida, kuidas teie programm ressursse eraldab. Illustreerimiseks kujutame ette, et peame looma lihtsa EC2 serveri ja tahame olla kindlad järgmises:

  • Juhtumitel on silt Name.
  • Eksemplarid ei tohiks kasutada tekstisisest skripti userData - peame kasutama AMI-d (pilti).
  • Internetis ei tohiks olla SSH-d.

See näide põhineb minu näide 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;

See on Pulumi põhiprogramm: see lihtsalt eraldab EC2 turberühma ja eksemplari. Siiski tuleb märkida, et siin rikume kõiki kolme ülaltoodud reeglit. Kirjutame teste!

Testide kirjutamine

Meie testide üldine struktuur näeb välja nagu tavalised Mocha testid:

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

Nüüd kirjutame oma esimese testi: veenduge, et eksemplaridel oleks silt Name. Selle kontrollimiseks hankime lihtsalt EC2 eksemplari objekti ja kontrollime vastavat omadust 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();
                }
            });
        });

See näeb välja nagu tavaline test, kuid sellel on mõned funktsioonid, mis väärivad tähelepanu.

  • Kuna me küsime enne juurutamist ressursi oleku, käitatakse meie testid alati plaani (või eelvaate) režiimis. Seega on palju atribuute, mille väärtusi lihtsalt ei leita või neid ei määrata. See hõlmab kõiki teie pilveteenuse pakkuja arvutatud väljundatribuute. See on meie testide puhul normaalne – kontrollime ainult sisendandmeid. Tuleme selle probleemi juurde hiljem tagasi, kui tegemist on integratsioonitestidega.
  • Kuna kõik Pulumi ressursi atribuudid on väljundid ja paljusid neist hinnatakse asünkroonselt, peame väärtustele juurdepääsuks kasutama rakendusmeetodit. See on väga sarnane lubadustele ja funktsioonidele then .
  • Kuna kasutame veateates ressursi URN kuvamiseks mitut atribuuti, peame kasutama funktsiooni pulumi.allneid kombineerida.
  • Lõpuks, kuna need väärtused arvutatakse asünkroonselt, peame kasutama Mocha sisseehitatud asünkroonse tagasihelistamise funktsiooni done või lubaduse tagastamine.

Kui oleme kõik seadistanud, on meil juurdepääs sisenditele lihtsate JavaScripti väärtustena. Kinnisvara tags on kaart (assotsiatiivne massiiv), nii et me lihtsalt veendume, et see (1) poleks vale ja (2) sellel on võti Name. See on väga lihtne ja nüüd saame kõike testida!

Nüüd kirjutame oma teise kontrolli. See on veelgi lihtsam:

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

Ja lõpuks kirjutame kolmanda testi. See on veidi keerulisem, kuna otsime turvagrupiga seotud sisselogimisreegleid, mida võib olla palju, ja CIDR-i vahemikke nendes reeglites, mida võib samuti olla palju. Aga saime hakkama:

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

See on kõik. Nüüd teeme testid!

Testide jooksmine

Enamikul juhtudel saate teste käivitada tavapärasel viisil, kasutades teie valitud testiraamistikku. Kuid Pulumil on üks omadus, millele tasub tähelepanu pöörata.
Tavaliselt kasutatakse Pulumi programmide käivitamiseks pulimi CLI-d (Command Line interface), mis konfigureerib keele käitusaja, juhib Pulumi mootori käivitamist, et ressurssidega tehtud toiminguid saaks salvestada ja plaani lisada jne. Siiski on üks probleem. Kui töötate oma testraamistiku kontrolli all, ei toimu CLI ja Pulumi mootori vahel sidet.

Selle probleemi lahendamiseks peame lihtsalt täpsustama järgmise:

  • Projekti nimi, mis sisaldub keskkonnamuutujas PULUMI_NODEJS_PROJECT (või üldisemalt PULUMI__PROJECT для других языков).
    Keskkonnamuutujas määratud virna nimi PULUMI_NODEJS_STACK (või üldisemalt PULUMI__ STACK).
    Teie virna konfiguratsioonimuutujad. Neid saab hankida keskkonnamuutuja abil PULUMI_CONFIG ja nende vorming on JSON-kaart võtme/väärtuse paaridega.

    Programm väljastab hoiatusi, mis näitavad, et ühendus CLI/mootoriga pole käivitamise ajal saadaval. See on oluline, sest teie programm ei juuruta tegelikult midagi ja kui te seda ei kavatsenud teha, võib see olla üllatus! Selleks, et öelda Pulumile, et see on just see, mida vajate, saate installida PULUMI_TEST_MODE в true.

    Kujutage ette, et peame määrama projekti nime my-ws, virna nimi devja AWS-i piirkond us-west-2. Mocha testide käitamise käsurida näeb välja järgmine:

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

    Kui teeme seda ootuspäraselt, näitame meile, et meil on kolm ebaõnnestunud testi!

    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

    Parandame oma programmi:

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

    Ja seejärel käivitage testid uuesti:

    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)

    Kõik läks hästi... Hurraa! ✓✓✓

    Tänaseks on see kõik, kuid juurutustestimisest räägime tõlke teises osas 😉

Allikas: www.habr.com

Lisa kommentaar