Pulumi менен код катары инфраструктураны сыноо. 1-бөлүк

Кутмандуу кеч достор. Темп боюнча жаңы агымдын башталышын күтүү менен "DevOps практикалары жана куралдары" Сиздер менен жаңы котормо менен бөлүшөбүз. Go.

Pulumi менен код катары инфраструктураны сыноо. 1-бөлүк

Инфраструктуралык код үчүн Pulumi жана жалпы максаттуу программалоо тилдерин колдонуу (Инфраструктура катары Код) көптөгөн артыкчылыктарды камсыз кылат: көндүмдөрдүн жана билимдердин болушу, абстракция аркылуу коддогу кампаны жок кылуу, IDE жана линтер сыяктуу командаңызга тааныш инструменттер. Бардык бул программалык камсыздоо инструменттери бизди жемиштүү кылып гана койбостон, кодубуздун сапатын да жакшыртат. Ошондуктан, жалпы максаттуу программалоо тилдерин колдонуу бизге программалык камсыздоону иштеп чыгуунун дагы бир маанилүү практикасын киргизүүгө мүмкүндүк берет - бул табигый нерсе - тестирлөө.

Бул макалада биз Пулуми инфраструктураны код катары сынап көрүүгө кандайча жардам берерин карап чыгабыз.

Pulumi менен код катары инфраструктураны сыноо. 1-бөлүк

Эмне үчүн инфраструктураны сыноо керек?

Майда-чүйдөсүнө чейин, "Эмне үчүн инфраструктураны сынап көрүү керек?" деген суроону берүү керек. Мунун көптөгөн себептери бар жана бул жерде алардын айрымдары:

  • Жеке функцияларды же программаңыздын логикасынын фрагменттерин тестирлөө
  • Белгилүү чектөөлөргө каршы инфраструктуранын каалаган абалын текшерет.
  • Сактагыч чака шифрлөөнүн жоктугу же Интернеттен виртуалдык машиналарга корголбогон, ачык кирүү сыяктуу жалпы каталарды аныктоо.
  • Инфраструктуралык камсыздоонун аткарылышын текшерүү.
  • Провизиялангандан кийин функционалдуулукту текшерүү үчүн "программаланган" инфраструктураңыздын ичинде иштеп жаткан колдонмо логикасынын иштөө убактысын текшерүү.
  • Көрүнүп тургандай, инфраструктураны тестирлөөнүн кеңири спектри бар. Полуми бул спектрдин ар бир чекитинде сыноо үчүн механизмдерге ээ. Келгиле, баштайлы жана анын кантип иштээрин карап көрөлү.

Бирдикти сыноо

Pulumi программалары JavaScript, Python, TypeScript же Go сыяктуу жалпы максаттуу программалоо тилдеринде жазылган. Ошондуктан, бул тилдердин толук күчү, анын ичинде алардын куралдары жана китепканалары, анын ичинде тест алкактары, алар үчүн жеткиликтүү. Pulumi көп булуттуу, демек, аны каалаган булут провайдеринен сыноо үчүн колдонсо болот.

(Бул макалада, көп тилдүү жана көп булуттуу болгонубузга карабастан, биз JavaScript жана Mocha колдонобуз жана AWSге көңүл бурабыз. Сиз Python колдоно аласыз. unittest, Сыноо алкагына же сизге жаккан башка тест алкагына өтүңүз. Жана, албетте, Pulumi Azure, Google Cloud, Kubernetes менен сонун иштейт.)

Биз көргөндөй, сиз инфраструктуралык кодуңузду сынап көргүңүз келген бир нече себептер бар. Алардын бири кадимки бирдик сыноо болуп саналат. Анткени сиздин кодуңузда функциялар болушу мүмкүн - мисалы, CIDRди эсептөө, аттарды, тегдерди жана башкалар. - Балким, сен аларды сынагың келет. Бул сүйүктүү программалоо тилиңизде тиркемелер үчүн кадимки тесттерди жазуу менен бирдей.
Бир аз татаалдануу үчүн, программаңыз ресурстарды кантип бөлүштүрөрүн текшере аласыз. Мисал үчүн, биз жөнөкөй EC2 серверин түзүшүбүз керек деп элестетип көрөлү жана биз төмөнкүлөргө ишенгибиз келет:

  • Инстанциялардын теги бар Name.
  • Instances inline скрипт колдонбошу керек 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;

Бул Пулумидин негизги программасы: ал жөн гана 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();
                }
            });
        });

Бул кадимки сыноо окшойт, бирок бир нече өзгөчөлүктөргө ээ:

  • Орнотуудан мурун биз ресурстун абалын сурагандыктан, биздин тесттер ар дайым "план" (же "алдын ала көрүү") режиминде жүргүзүлөт. Ошентип, баалуулуктары жөн эле алынбай турган же аныкталбай турган көптөгөн касиеттер бар. Бул сиздин булут камсыздоочу тарабынан эсептелген бардык чыгаруу касиеттерин камтыйт. Бул биздин тесттер үчүн нормалдуу көрүнүш - биз киргизилген маалыматтарды гана текшеребиз. Биз бул маселеге кийинчерээк, интеграциялык тесттерге келгенде кайрылабыз.
  • Бардык Пулуми ресурстук касиеттери чыгарылыш болгондуктан жана алардын көбү асинхрондук түрдө баалангандыктан, баалуулуктарга жетүү үчүн колдонуу ыкмасын колдонушубуз керек. Бул убадаларга жана функцияларга абдан окшош 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 интерфейси) колдонулат, ресурстар менен операциялар жазылып, планга киргизилиши үчүн Plumi кыймылдаткычынын ишке киришин башкарат. Бирок, бир көйгөй бар. Сыноо алкагыңыздын көзөмөлү астында иштеп жатканда, CLI менен Пулуми кыймылдаткычынын ортосунда эч кандай байланыш болбойт.

Бул маселени чечүү үчүн, биз жөн гана төмөнкүлөрдү белгилешибиз керек:

  • Айлана-чөйрө өзгөрмөсүндө камтылган долбоордун аталышы 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)

    Баары жакшы өттү... Урра! ✓✓✓

    Мунун баары бүгүн, бирок биз котормонун экинчи бөлүгүндө жайылтуу тести жөнүндө сүйлөшөбүз 😉

Source: www.habr.com

Комментарий кошуу