Тестирање на инфраструктурата како код со Pulumi. Дел 1

Добро попладне пријатели. Во пресрет на почеток на нов проток по стапка „Практики и алатки на DevOps“ Со вас споделуваме нов превод. Оди.

Тестирање на инфраструктурата како код со Pulumi. Дел 1

Користењето на Пулуми и програмските јазици за општа намена за инфраструктурен код (Инфраструктура како код) дава многу предности: достапност на вештини и знаења, елиминација на плочата во кодот преку апстракција, алатки познати на вашиот тим, како што се IDE и линтери. Сите овие софтверски инженерски алатки не само што не прават попродуктивни, туку и го подобруваат квалитетот на нашиот код. Затоа, сосема е природно што употребата на програмски јазици за општа намена ни овозможува да воведеме уште една важна практика за развој на софтвер - Тестирање.

Во оваа статија, ќе погледнеме како Pulumi ни помага да ја тестираме нашата инфраструктура како код.

Тестирање на инфраструктурата како код со Pulumi. Дел 1

Зошто да се тестира инфраструктурата?

Пред да навлегуваме во детали, вреди да се постави прашањето: „Зошто воопшто да се тестира инфраструктурата? Постојат многу причини за ова, а еве неколку од нив:

  • Единица за тестирање на поединечни функции или фрагменти од вашата програмска логика
  • Ја потврдува посакуваната состојба на инфраструктурата наспроти одредени ограничувања.
  • Откривање на вообичаени грешки, како што е недостаток на шифрирање на кофа за складирање или незаштитен, отворен пристап од Интернет до виртуелни машини.
  • Проверка на спроведувањето на обезбедувањето инфраструктура.
  • Извршување на тестирање за време на траење на логиката на апликацијата што се извршува во вашата „програмирана“ инфраструктура за да се провери функционалноста по обезбедувањето.
  • Како што можеме да видиме, има широк спектар на опции за тестирање на инфраструктурата. Polumi има механизми за тестирање на секоја точка од овој спектар. Ајде да започнеме и да видиме како функционира.

Единица тестирање

Програмите на Pulumi се напишани на програмски јазици за општа намена како што се JavaScript, Python, TypeScript или Go. Затоа, целосната моќ на овие јазици, вклучувајќи ги нивните алатки и библиотеки, вклучително и тест рамки, им е достапна. Pulumi е мулти-облак, што значи дека може да се користи за тестирање од кој било провајдер на облак.

(Во оваа статија, и покрај тоа што е повеќејазичен и повеќеоблак, ние користиме JavaScript и Mocha и се фокусираме на AWS. Можете да користите Python unittest, Go test рамка или која било друга рамка за тестирање што ја сакате. И, се разбира, Пулуми работи одлично со Azure, Google Cloud, Kubernetes.)

Како што видовме, постојат неколку причини зошто можеби сакате да го тестирате вашиот инфраструктурен код. Еден од нив е конвенционално тестирање на единици. Бидејќи вашиот код може да има функции - на пример, за пресметување на CIDR, динамички пресметување имиња, ознаки итн. - веројатно ќе сакате да ги тестирате. Ова е исто како да пишувате редовни единечни тестови за апликации на вашиот омилен програмски јазик.
За да станете малку покомплицирани, можете да проверите како вашата програма ги распределува ресурсите. За илустрација, да замислиме дека треба да создадеме едноставен сервер EC2 и сакаме да бидеме сигурни во следново:

  • Примерите имаат ознака Name.
  • Случаите не треба да користат вградена скрипта userData - мора да користиме AMI (слика).
  • Не треба да има SSH изложен на Интернет.

Овој пример се заснова на мојот пример 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;

Ова е основната програма на Pulumi: таа едноставно доделува безбедносна група EC2 и примерок. Сепак, треба да се забележи дека овде ги прекршуваме сите три правила наведени погоре. Ајде да пишуваме тестови!

Тестови за пишување

Општата структура на нашите тестови ќе изгледа како редовни тестови за Мока:

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

Сега да го напишеме нашиот прв тест: проверете дали инстанците имаат ознака Name. За да го провериме ова, едноставно го добиваме објектот на примерот EC2 и го проверуваме соодветното својство 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();
                }
            });
        });

Изгледа како редовен тест, но со неколку карактеристики што вреди да се забележат:

  • Бидејќи ја бараме состојбата на ресурсот пред распоредувањето, нашите тестови секогаш се извршуваат во режимот „план“ (или „преглед“). Така, има многу својства чии вредности едноставно нема да се вратат или нема да се дефинираат. Ова ги вклучува сите излезни својства пресметани од вашиот обезбедувач на облак. Ова е нормално за нашите тестови - ги проверуваме само влезните податоци. На ова прашање ќе се вратиме подоцна, кога станува збор за тестовите за интеграција.
  • Бидејќи сите својства на ресурсите на Пулуми се излези, а многу од нив се оценуваат асинхроно, треба да го користиме методот примени за да пристапиме до вредностите. Ова е многу слично на ветувањата и функционирањето then .
  • Бидејќи користиме неколку својства за да го прикажеме URN на ресурсот во пораката за грешка, треба да ја користиме функцијата pulumi.allда ги комбинирате.
  • Конечно, бидејќи овие вредности се пресметуваат асинхроно, треба да ја користиме вградената функција за асинхроно повратен повик на Мока done или враќање на ветувањето.

Откако ќе поставиме сè, ќе имаме пристап до влезовите како едноставни вредности на JavaScript. Имотот tags е мапа (асоцијативна низа), па само ќе се погрижиме да не е (1) неточно и (2) да има клуч за Name. Многу е едноставно и сега можеме да тестираме сè!

Сега да ја напишеме нашата втора проверка. Уште поедноставно е:

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

И конечно, да го напишеме третиот тест. Ова ќе биде малку покомплицирано бидејќи ги бараме правилата за најавување поврзани со безбедносната група, од кои може да има многу, и опсегот CIDR во тие правила, од кои исто така може да има многу. Но, успеавме:

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

Тоа е се. Сега да ги извршиме тестовите!

Водење тестови

Во повеќето случаи, можете да извршите тестови на вообичаен начин, користејќи ја рамката за тестирање по ваш избор. Но, постои една карактеристика на Пулуми на која вреди да се обрне внимание.
Вообичаено, за извршување на програмите на Pulumi, се користи pulimi CLI (интерфејс на командната линија), кој го конфигурира времето на работа на јазикот, го контролира стартувањето на моторот Pulumi, така што операциите со ресурси може да се снимаат и да се вклучат во планот итн. Сепак, постои еден проблем. Кога работи под контрола на вашата рамка за тестирање, нема да има комуникација помеѓу CLI и моторот Pulumi.

За да го заобиколиме овој проблем, само треба да го наведеме следново:

  • Име на проектот, кое е содржано во променливата на животната средина PULUMI_NODEJS_PROJECT (или, поопшто, PULUMI__PROJECT для других языков).
    Името на стекот што е наведено во променливата на околината PULUMI_NODEJS_STACK (или, поопшто, PULUMI__ STACK).
    Вашите променливи за конфигурација на стек. Тие можат да се добијат со помош на променлива на околината PULUMI_CONFIG а нивниот формат е JSON карта со парови клучеви/вредности.

    Програмата ќе издаде предупредувања што укажуваат дека врската со CLI/моторот не е достапна за време на извршувањето. Ова е важно затоа што вашата програма всушност нема да распореди ништо и може да биде изненадување ако тоа не е она што сте сакале да го направите! За да му кажете на Пулуми дека тоа е токму она што ви треба, можете да инсталирате PULUMI_TEST_MODE в true.

    Замислете дека треба да го наведеме името на проектот my-ws, име на магацинот dev, и AWS регионот us-west-2. Командната линија за извршување на тестовите Мока ќе изгледа вака:

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

    Ако го направите ова, очекувано, ќе ни покаже дека имаме три неуспешни тестови!

    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

    Ајде да ја поправиме нашата програма:

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

    И потоа извршете ги тестовите повторно:

    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)

    Сè помина добро... Ура! ✓✓✓

    Тоа е сè за денес, но ќе зборуваме за тестирање за распоредување во вториот дел од преводот 😉

Извор: www.habr.com

Додадете коментар