Pulumi көмегімен код ретінде инфрақұрылымды сынау. 1 бөлім

Қайырлы күн достар. қарқынмен жаңа ағынның басталуын күтумен «DevOps тәжірибелері мен құралдары» Біз сіздермен жаңа аудармамен бөлісеміз. Бар.

Pulumi көмегімен код ретінде инфрақұрылымды сынау. 1 бөлім

Инфрақұрылымдық код үшін Pulumi және жалпы мақсаттағы бағдарламалау тілдерін пайдалану (Infrastructure as Code) көптеген артықшылықтарды қамтамасыз етеді: дағдылар мен білімнің қолжетімділігі, абстракция арқылы кодтағы қарапайым тақтаны жою, IDE және линтер сияқты командаңызға таныс құралдар. Бағдарламалық жасақтаманың барлық осы құралдары бізді өнімдірек етіп қана қоймайды, сонымен қатар кодымыздың сапасын жақсартады. Сондықтан, жалпы мақсаттағы бағдарламалау тілдерін пайдалану бізге бағдарламалық жасақтаманы әзірлеудің тағы бір маңызды тәжірибесін енгізуге мүмкіндік беретіні табиғи нәрсе - Тестілеу.

Бұл мақалада біз Пулуми инфрақұрылымды код ретінде сынауға қалай көмектесетінін қарастырамыз.

Pulumi көмегімен код ретінде инфрақұрылымды сынау. 1 бөлім

Неліктен инфрақұрылымды сынау керек?

Егжей-тегжейлі айтпас бұрын, «Неліктен инфрақұрылымды сынау керек?» Деген сұрақты қойған жөн. Мұның көптеген себептері бар және олардың кейбіреулері:

  • Жеке функцияларды немесе бағдарлама логикасының фрагменттерін бірлік тестілеу
  • Белгілі бір шектеулерге қарсы инфрақұрылымның қалаған күйін тексереді.
  • Сақтау шелегін шифрлаудың болмауы немесе Интернеттен виртуалды машиналарға қорғалмаған, ашық қолжетімділік сияқты жалпы қателерді анықтау.
  • Инфрақұрылымдық қамтамасыз етудің орындалуын тексеру.
  • Қамтамасыз етуден кейін функционалдылықты тексеру үшін «бағдарламаланған» инфрақұрылымыңызда іске қосылған қолданба логикасын орындау уақытын тексеру.
  • Көріп отырғанымыздай, инфрақұрылымды сынау нұсқаларының кең ауқымы бар. Полумиде осы спектрдің әрбір нүктесінде тестілеу механизмдері бар. Бастайық және оның қалай жұмыс істейтінін көрейік.

Бірлікті сынау

Pulumi бағдарламалары JavaScript, Python, TypeScript немесе Go сияқты жалпы мақсаттағы бағдарламалау тілдерінде жазылған. Сондықтан бұл тілдердің толық күші, соның ішінде құралдары мен кітапханалары, соның ішінде сынақ құрылымдары оларға қол жетімді. Pulumi көп бұлтты, яғни оны кез келген бұлттық провайдерден тестілеу үшін пайдалануға болады.

(Бұл мақалада көптілді және көп бұлтты болуына қарамастан, біз JavaScript және Mocha пайдаланамыз және AWS-ге назар аударамыз. Python-ды пайдалана аласыз. unittest, Сынақ құрылымына немесе өзіңізге ұнайтын кез келген басқа сынақ шеңберіне өтіңіз. Және, әрине, Пулуми 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 қауіпсіздік тобын және данасын бөледі. Дегенмен, бұл жерде біз жоғарыда айтылған үш ережені де бұзып жатқанымызды атап өткен жөн. Тесттер жазайық!

Жазбаша тесттер

Біздің сынақтарымыздың жалпы құрылымы әдеттегі Mocha сынақтарына ұқсайды:

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

Бұл әдеттегі сынаққа ұқсайды, бірақ бірнеше ерекшеліктері бар:

  • Орналастыру алдында ресурс күйін сұрайтындықтан, сынақтар әрқашан «жоспар» (немесе «алдын ала қарау») режимінде орындалады. Осылайша, мәндері жай ғана алынбайтын немесе анықталмайтын көптеген қасиеттер бар. Бұған бұлттық провайдер есептеген барлық шығыс сипаттары кіреді. Бұл біздің сынақтарымыз үшін қалыпты жағдай - біз тек кіріс деректерін тексереміз. Біз бұл мәселеге кейінірек, интеграциялық сынақтарға келгенде қайта ораламыз.
  • Барлық Pulumi ресурс сипаттары шығыс болып табылатындықтан және олардың көпшілігі асинхронды түрде бағаланатындықтан, мәндерге қол жеткізу үшін қолдану әдісін пайдалануымыз керек. Бұл уәделер мен функцияларға өте ұқсас then .
  • Қате туралы хабарда URN ресурсын көрсету үшін бірнеше сипаттарды пайдаланып жатқандықтан, функцияны пайдалануымыз керек pulumi.allоларды біріктіру.
  • Соңында, бұл мәндер асинхронды түрде есептелетіндіктен, біз Mocha кірістірілген асинхронды кері шақыру мүмкіндігін пайдалануымыз керек. 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 (Command Line интерфейсі) пайдаланылады, ресурстармен операциялар жазылуы және жоспарға енгізілуі үшін 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. Mocha сынақтарын іске қосу пәрмен жолы келесідей болады:

    $ 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

пікір қалдыру