Dobrý den, přátelé. Před zahájením nového cyklu kurzu sdílíme s vámi nový překlad. Jdeme na to.

Použití Pulumi a obecných programovacích jazyků pro infrastrukturní kód (Infrastructure as Code) přináší mnoho výhod: dovednosti a znalosti, odstranění boilerplate kódu prostřednictvím abstrakce, nástroje, které zná váš tým, jako IDE a lintery. Všechny tyto nástroje softwarového inženýrství nejen zvyšují naši produktivitu, ale také zlepšují kvalitu kódu. Proto je zcela přirozené, že použití obecných programovacích jazyků umožňuje zavést další důležitou praxi vývoje softwaru – testování.
V tomto článku se podíváme, jak Pulumi pomáhá testovat naši „infrastrukturu jako kód“.

Proč testovat infrastrukturu?
Než se pustíme do podrobností, je dobré si položit otázku: „Proč vůbec testovat infrastrukturu?“ Důvodů je mnoho a zde jsou některé z nich:
- Modulární testování jednotlivých funkcí nebo částí logiky vaší aplikace.
- Ověření požadovaného stavu infrastruktury podle specifikovaných omezení.
- Odhalení běžných chyb, jako je absence šifrování storage bucket nebo nezabezpečený, otevřený přístup z internetu k virtuálním strojům.
- Ověření provedení provisioning infrastruktury.
- Provádění runtime testování logiky aplikace spuštěné uvnitř vaší „naprogramované“ infrastruktury za účelem ověření funkčnosti po provisioning.
- Jak vidíme, existuje široké spektrum možností testování infrastruktury. V Pulumi jsou k dispozici mechanismy pro testování v každém bodě tohoto spektra. Pojďme začít a podívat se, jak to funguje.
Modulární testování
Pulumi programy se vytvářejí v obecných programovacích jazycích, jako jsou JavaScript, Python, TypeScript nebo Go. Proto mají k dispozici plnou sílu těchto jazyků, včetně jejich nástrojů a knihoven, včetně testovacích frameworků. Pulumi je multi-cloudové, což znamená, že pro testy je možné použít libovolné poskytovatele cloudových služeb.
(V tomto článku, i když se zaměřujeme na vícejazyčnost a multi-cloudovost, používáme JavaScript a Mocha a zaměřujeme se na AWS. Můžete použít Python unittest, testovací framework Go nebo jakýkoli jiný oblíbený framework. A samozřejmě, Pulumi skvěle funguje s Azure, Google Cloud, Kubernetes.)
Jak jsme viděli, existuje několik důvodů, proč byste měli testovat svůj infrastrukturní kód. Jedním z nich je běžné modulární testování. Protože váš kód může mít funkce – například pro výpočet CIDR, dynamické generování názvů, tagů atd. – pravděpodobně je budete chtít otestovat. To je stejné jako psaní běžných modulárních testů pro aplikace ve vašem oblíbeném programovacím jazyce.
Pokud bychom to trochu zkomplikovali, můžeme ověřit, jak vaše aplikace rozděluje prostředky. Pro ilustraci si představme, že potřebujeme vytvořit jednoduchý EC2 server a chceme si ujistit, že:
- Instance mají tag
Název. - Instance nesmí používat inline skript
userData– musíme použít AMI (obraz). - Nemělo by být SSH otevřené na internet.
Tento příklad byl napsán na základě :
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 pro us-east-2 (Ohio),
userData: userData \/\/ spuštění jednoduchého webového serveru
});
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;
Toto je základní program Pulumi: jednoduše alokuje skupinu zabezpečení EC2 a instanci. Je však třeba poznamenat, že zde porušujeme všechna tři pravidla uvedená výše. Pojďme psát testy!
Píšeme testy
Celková struktura našich testů bude vypadat jako běžné Mocha testy:
ec2tests.js
test.js:
let assert = require("assert");
let mocha = require("mocha");
let pulumi = require("@pulumi/pulumi");
let infra = require("./index");
describe("Infrastruktura", function() {
let server = infra.server;
describe("#server", function() {
\/\/ TODO(check 1): Měl by být tag Name.
\/\/ TODO(check 2): Nemělo by být inline skript userData.
});
let group = infra.group;
describe("#group", function() {
\/\/ TODO(check 3): Nemělo by být SSH otevřené na internet.
});
}); Teď pojďme napsat náš první test: ujistit se, že instance mají tag Název. Pro ověření toho jednoduše získáme objekt EC2 instance a zkontrolujeme odpovídající vlastnost. 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();
}
});
});Vypadá to jako běžný test, ale má několik zajímavých vlastností:
- Protože před nasazením zjišťujeme stav zdroje, naše testy se vždy provádějí v režimu „plan“ (nebo „preview“). Výsledkem je, že mnoho vlastností, jejichž hodnoty nejsou zjištěny nebo jsou neznámé, nebude dostupných. To zahrnuje všechny výstupní vlastnosti, které vypočítává váš cloudový poskytovatel. Pro naše testy je to v pořádku - kontrolujeme pouze vstupy. K tomuto tématu se vrátíme později, když se budeme zabývat integračními testy.
- Protože všechna vlastnosti Pulumi zdrojů jsou „výstupy“ a mnohé z nich se počítají asynchronně, je třeba použít metodu apply pro získání hodnot. To velmi připomíná přísliby a funkce.
then. - Protože používáme několik vlastností k zobrazení URN zdroje v chybovém hlášení, musíme použít funkci
pulumi.all, abychom je spojili. - Nakonec, protože tyto hodnoty se počítají asynchronně, musíme použít vestavěnou asynchronní funkčnost Mocha s callbackem
donenebo vrácením příslibu.
Jakmile máme vše nastaveno, budeme mít přístup k vstupům jako k jednoduchým hodnotám JavaScriptu. Vlastnost tags je map (asociativní pole), takže se jednoduše ujistíme, že (1) není false, a (2) existuje klíč pro Název. Je to velmi jednoduché a nyní můžeme prověřit cokoliv!
Teď pojďme napsat naši druhou kontrolu. To je ještě jednodušší:
// 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();
}
});
});A nakonec napišme třetí test. Ten bude o něco složitější, protože hledáme pravidla pro přístup spojená s bezpečnostní skupinou, kterých může být mnoho, a rozsahy CIDR v těchto pravidlech, kterých může být také mnoho. Ale zvládli jsme to:
// 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();
}
});
});To je všechno. Teď pojďme spustit testy!
Spouštění testů
Testy se většinou spouštějí standardním způsobem pomocí vámi zvoleného testovacího rámce. Ale existuje jedna zvláštnost Pulumi, na kterou stojí za to upozornit.
Obvykle se pro spuštění Pulumi programů používá pulumi CLI (Command Line Interface), které nastavuje runtime jazyka, řídí spuštění motoru Pulumi, aby bylo možné zaznamenávat operace se zdroji a zahrnout je do plánu atd. Existuje však jeden problém. Při spuštění pod kontrolou vaší testovací frameworku nebude spojení mezi CLI a motorem Pulumi.
Abychom tento problém obešli, stačí uvést následující:
- Jméno projektu, které je obsaženo v proměnné prostředí
PULUMI_NODEJS_PROJECT(nebo, v obecnějším případě,PULUMI__PROJECT pro jiné jazyky).
Jméno stacku, které je uvedeno v proměnné prostředíPULUMI_NODEJS_STACK(nebo, v obecnějším případě,PULUMI__STACK).
Vaše proměnné konfigurace stacku. Mohou být získány pomocí proměnné prostředíPULUMI_CONFIGa jejich formát představuje JSON mapu s dvojicemi klíč/hodnota.Program zobrazí upozornění, říkající, že během provádění není dostupné spojení s CLI/motorem. To je důležité, protože vaše program skutečně nic nenasadí a to může být překvapením, pokud to není to, co jste chtěli udělat! Abychom Pulumi řekli, že to je přesně to, co potřebujete, můžete nastavit
PULUMI_TEST_MODEvtrue.Představte si, že potřebujeme uvést název projektu jako
my-ws, název stackudev, a region AWSus-west-2. Příkazová řádka pro spuštění testů Mocha bude vypadat následovně:$ PULUMI_TEST_MODE=true PULUMI_NODEJS_STACK="my-ws" PULUMI_NODEJS_PROJECT="dev" PULUMI_CONFIG='{ "aws:region": "us-west-2" }' mocha tests.jsProvádění tohoto, jak bylo očekáváno, nám ukáže, že máme tři selhané testy!
Infrastructure #server 1) musí mít tag s názvem 2) nesmí používat userData (použijte AMI místo toho) #group 3) nesmí otevřít port 22 (SSH) pro Internet 0 úspěšně (17ms) 3 selhání 1) Infrastructure #server musí mít tag s názvem: Chyba: Chybí tag s názvem na serveru urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www 2) Infrastructure #server nesmí používat userData (použijte AMI místo toho): Chyba: Nelegální použití userData na serveru urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www 3) Infrastructure #group nesmí otevřít port 22 (SSH) pro Internet: Chyba: Nelegální SSH port 22 otevřený pro Internet (CIDR 0.0.0.0/0) na skupiněOpraveníme naši program:
"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;A poté znovu spustíme testy:
Infrastruktura #server ✓ musí mít název ✓ nesmí používat userData (místo toho použijte AMI) #group ✓ nesmí otevřít port 22 (SSH) pro internet 3 úspěšné (16ms)Všechno proběhlo úspěšně… Hurá! ✓✓✓
Na dnešek je to vše, o testování nasazení si popovídáme v druhé části překladu 😉
Zdroj: habr.com
