Infrastruktūras kā koda testēšana ar Pulumi. 1. daļa

Labdien draugi. Sagaidot jaunas plūsmas sākumu ar ātrumu "DevOps prakse un rīki" Mēs dalāmies ar jums ar jaunu tulkojumu. Aiziet.

Infrastruktūras kā koda testēšana ar Pulumi. 1. daļa

Izmantojot Pulumi un vispārējas nozīmes programmēšanas valodas infrastruktūras kodam (Infrastructure as Code), tiek nodrošinātas daudzas priekšrocības: prasmju un zināšanu pieejamība, abstrakcijas rezultātā tiek novērsta šifra plāksne, jūsu komandai pazīstami rīki, piemēram, IDE un linteri. Visi šie programmatūras inženierijas rīki ne tikai padara mūs produktīvākus, bet arī uzlabo mūsu koda kvalitāti. Tāpēc ir tikai dabiski, ka vispārējas nozīmes programmēšanas valodu izmantošana ļauj mums ieviest vēl vienu svarīgu programmatūras izstrādes praksi - testēšana.

Šajā rakstā mēs apskatīsim, kā Pulumi palīdz mums pārbaudīt mūsu infrastruktūru kā kodu.

Infrastruktūras kā koda testēšana ar Pulumi. 1. daļa

Kāpēc pārbaudīt infrastruktūru?

Pirms iedziļināties detaļās, ir vērts uzdot jautājumu: "Kāpēc vispār pārbaudīt infrastruktūru?" Tam ir daudz iemeslu, un šeit ir daži no tiem:

  • Atsevišķu funkciju vai programmas loģikas fragmentu vienību pārbaude
  • Pārbauda vēlamo infrastruktūras stāvokli pret noteiktiem ierobežojumiem.
  • Bieži sastopamu kļūdu noteikšana, piemēram, krātuves kopas šifrēšanas trūkums vai neaizsargāta, atvērta piekļuve virtuālajām mašīnām no interneta.
  • Infrastruktūras nodrošināšanas ieviešanas pārbaude.
  • Lietojumprogrammu loģikas izpildlaika testēšana, kas darbojas jūsu “ieprogrammētajā” infrastruktūrā, lai pārbaudītu funkcionalitāti pēc nodrošināšanas.
  • Kā redzam, infrastruktūras testēšanas iespēju klāsts ir ļoti plašs. Polumi ir mehānismi testēšanai katrā šī spektra punktā. Sāksim un redzēsim, kā tas darbojas.

Vienības pārbaude

Pulumi programmas ir rakstītas vispārējas nozīmes programmēšanas valodās, piemēram, JavaScript, Python, TypeScript vai Go. Tāpēc viņiem ir pieejams visas šo valodu iespējas, tostarp to rīki un bibliotēkas, tostarp testa ietvari. Pulumi ir daudzmākoņu sistēma, kas nozīmē, ka to var izmantot testēšanai no jebkura mākoņa pakalpojumu sniedzēja.

(Šajā rakstā mēs izmantojam JavaScript un Mocha, neskatoties uz to, ka tas ir daudzvalodu un daudzmākoņu, un koncentrējamies uz AWS. Varat izmantot Python unittest, Go testa ietvaru vai jebkuru citu testa sistēmu, kas jums patīk. Un, protams, Pulumi lieliski darbojas ar Azure, Google Cloud, Kubernetes.)

Kā mēs redzējām, ir vairāki iemesli, kāpēc jūs varētu vēlēties pārbaudīt savu infrastruktūras kodu. Viens no tiem ir parastā vienību pārbaude. Tā kā jūsu kodam var būt funkcijas, piemēram, lai aprēķinātu CIDR, dinamiski aprēķinātu nosaukumus, atzīmes utt. - Jūs droši vien vēlēsities tos pārbaudīt. Tas ir tas pats, kas rakstīt regulārus vienību testus lietojumprogrammām jūsu iecienītākajā programmēšanas valodā.
Lai padarītu to nedaudz sarežģītāku, varat pārbaudīt, kā jūsu programma piešķir resursus. Lai ilustrētu, iedomāsimies, ka mums ir jāizveido vienkāršs EC2 serveris, un mēs vēlamies būt pārliecināti par sekojošo:

  • Gadījumiem ir atzīme Name.
  • Gadījumos nedrīkst izmantot iekļauto skriptu userData - mums ir jāizmanto AMI (attēls).
  • SSH nedrīkst būt pakļauts internetam.

Šis piemērs ir balstīts uz mans piemērs 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;

Šī ir pamata Pulumi programma: tā vienkārši piešķir EC2 drošības grupu un gadījumu. Tomēr jāatzīmē, ka šeit mēs pārkāpjam visus trīs iepriekš minētos noteikumus. Rakstīsim kontroldarbus!

Rakstīšanas testi

Mūsu testu vispārējā struktūra izskatīsies kā parasti Mocha testi:

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

Tagad uzrakstīsim savu pirmo testu: pārliecinieties, vai gadījumiem ir tags Name. Lai to pārbaudītu, mēs vienkārši iegūstam EC2 instances objektu un pārbaudām atbilstošo rekvizītu 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();
                }
            });
        });

Tas izskatās kā parasts tests, taču tajā ir dažas funkcijas, kuras ir vērts atzīmēt:

  • Tā kā pirms izvietošanas mēs vaicājam par resursa stāvokli, mūsu testi vienmēr tiek izpildīti “plāna” (vai “priekšskatījuma”) režīmā. Tādējādi ir daudz rekvizītu, kuru vērtības vienkārši netiks izgūtas vai netiks definētas. Tas ietver visus izvades rekvizītus, ko aprēķinājis jūsu mākoņa pakalpojumu sniedzējs. Tas ir normāli mūsu testos — mēs pārbaudām tikai ievades datus. Mēs atgriezīsimies pie šī jautājuma vēlāk, kad runa ir par integrācijas testiem.
  • Tā kā visi Pulumi resursu rekvizīti ir izvadi un daudzi no tiem tiek novērtēti asinhroni, mums ir jāizmanto pielietošanas metode, lai piekļūtu vērtībām. Tas ir ļoti līdzīgs solījumiem un afunction then .
  • Tā kā mēs izmantojam vairākus rekvizītus, lai kļūdas ziņojumā parādītu resursa URN, mums ir jāizmanto funkcija pulumi.alllai tās apvienotu.
  • Visbeidzot, tā kā šīs vērtības tiek aprēķinātas asinhroni, mums ir jāizmanto Mocha iebūvētā asinhronā atzvanīšanas funkcija done vai atdot solījumu.

Kad būsim visu iestatījuši, mēs varēsim piekļūt ievades datiem kā vienkāršām JavaScript vērtībām. Īpašums tags ir karte (asociatīvais masīvs), tāpēc mēs tikai pārliecināsimies, ka (1) tā nav nepatiesa un (2) ir atslēga Name. Tas ir ļoti vienkārši, un tagad mēs varam pārbaudīt jebko!

Tagad rakstīsim savu otro čeku. Tas ir vēl vienkāršāk:

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

Un visbeidzot, rakstīsim trešo testu. Tas būs nedaudz sarežģītāk, jo mēs meklējam ar drošības grupu saistītos pieteikšanās noteikumus, kuru var būt daudz, un CIDR diapazonus šajos noteikumos, kuru arī var būt daudz. Bet mums izdevā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();
                }
            });
        });

Tas ir viss. Tagad izpildīsim testus!

Skriešanas testi

Vairumā gadījumu jūs varat palaist testus parastajā veidā, izmantojot jūsu izvēlēto testa sistēmu. Bet ir viena Pulumi iezīme, kurai ir vērts pievērst uzmanību.
Parasti Pulumi programmu palaišanai tiek izmantots pulimi CLI (Command Line interfeiss), kas konfigurē valodas izpildlaiku, kontrolē Pulumi dzinēja palaišanu, lai operācijas ar resursiem varētu ierakstīt un iekļaut plānā utt. Tomēr ir viena problēma. Darbojoties jūsu testa ietvara kontrolē, starp CLI un Pulumi dzinēju nebūs saziņas.

Lai apietu šo problēmu, mums vienkārši jānorāda tālāk norādītā informācija.

  • Projekta nosaukums, kas ir ietverts vides mainīgajā PULUMI_NODEJS_PROJECT (vai vispārīgāk, PULUMI__PROJECT для других языков).
    Tās steka nosaukums, kas norādīts vides mainīgajā PULUMI_NODEJS_STACK (vai vispārīgāk, PULUMI__ STACK).
    Jūsu steka konfigurācijas mainīgie. Tos var iegūt, izmantojot vides mainīgo PULUMI_CONFIG un to formāts ir JSON karte ar atslēgu/vērtību pāriem.

    Programma izdos brīdinājumus, norādot, ka izpildes laikā savienojums ar CLI/dzinēju nav pieejams. Tas ir svarīgi, jo jūsu programma faktiski neko neizvietos, un tas var būt pārsteigums, ja tas nav tas, ko jūs plānojāt darīt! Lai pateiktu Pulumi, ka tas ir tieši tas, kas jums nepieciešams, varat instalēt PULUMI_TEST_MODE в true.

    Iedomājieties, ka mums ir jānorāda projekta nosaukums my-ws, steka nosaukums devun AWS reģionā us-west-2. Komandrinda Mocha testu palaišanai izskatīsies šādi:

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

    To darot, kā paredzēts, mēs parādīsim, ka mums ir trīs nesekmīgi 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

    Labosim savu programmu:

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

    Un pēc tam palaidiet testus vēlreiz:

    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)

    Viss gāja labi... Urā! ✓✓✓

    Šodien tas ir viss, bet par izvietošanas testēšanu mēs runāsim tulkojuma otrajā daļā 😉

Avots: www.habr.com

Pievieno komentāru