Dobar dan, prijatelji. Uoči novog ciklusa tečaja dijelimo s vama novi prijevod. Idemo.

Korištenje Pulumi i jezika opće namjene za infrastrukturni kod (Infrastructure as Code) donosi mnoge prednosti: posjedovanje vještina i znanja, eliminaciju šablonskog koda putem apstrakcije, poznate alate vašem timu, kao što su IDE i linteri. Svi ovi alati inženjeringa softvera ne samo da nas čine produktivnijima, nego i poboljšavaju kvalitetu koda. Stoga nije iznenađujuće što korištenje jezika opće namjene omogućava uvođenje još jedne važne prakse razvoja softvera — testiranje.
U ovom članku ćemo razmotriti kako Pulumi pomaže u testiranju naše „infrastrukture kao kod“.

Zašto testirati infrastrukturu?
Prije nego što se upustimo u detalje, vrijedi postaviti pitanje: „Zašto uopće testirati infrastrukturu?“ Ima mnogo razloga za to, a evo nekih od njih:
- Modularno testiranje pojedinih funkcija ili dijelova logike vaše aplikacije.
- Provjera željenog stanja infrastrukture prema određenim ograničenjima.
- Otkrivanje uobičajenih pogrešaka, poput nedostatka enkripcije storage bucketa ili nezaštićenog, otvorenog pristupa s Interneta na virtualne mašine.
- Provjera izvršenosti provisioninga infrastrukture.
- Izvođenje runtime testiranja logike aplikacije koja se pokreće unutar vaše „programirane“ infrastrukture radi provjere funkcionalnosti nakon provisioninga.
- Kako vidimo, postoji širok spektar opcija za testiranje infrastrukture. U Pulumi postoje mehanizmi za testiranje na svakoj točki tog spektra. Idemo dalje i pogledajmo kako to funkcionira.
Modularno testiranje
Pulumi programi se stvaraju na jezicima opće namjene, kao što su JavaScript, Python, TypeScript ili Go. Stoga je dostupna sva moć tih jezika, uključujući njihove alate i biblioteke, uključujući i testne okvire. Pulumi je multi-cloud, što znači mogućnost korištenja bilo kojeg cloud providera za testove.
(U ovom članku, unatoč višekratnosti jezika i multi-cloud pristupu, koristimo JavaScript i Mocha, fokusirajući se na AWS. Možete koristiti Python unittest, testni okvir Go ili bilo koji drugi omiljeni okvir za testiranje. I, naravno, Pulumi odlično radi s Azure, Google Cloud, Kubernetes.)
Kao što smo vidjeli, postoji nekoliko razloga zbog kojih može biti potrebno testirati vaš infrastrukturni kod. Jedan od njih je uobičajeno modularno testiranje. Budući da vaš kod može imati funkcije — na primjer, za izračun CIDR-a, dinamičko generiranje imena, oznaka itd. — vjerojatno ćete ih htjeti testirati. To je isto kao pisanje uobičajenih modularnih testova za aplikacije na vašem omiljenom programskom jeziku.
Ako malo zakompliciramo, možemo provjeriti kako vaša aplikacija raspodjeljuje resurse. Da bismo ilustrirali, zamislimo da trebamo stvoriti jednostavan EC2 poslužitelj i želimo biti sigurni u sljedeće:
- Instanci imaju oznaku
Name. - Instanci ne smiju koristiti inline-skriptu
userData— moramo koristiti AMI (sliku). - Ne smije biti SSH-a otvorenog za internet.
Ovaj primjer je napisan inspiriran :
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 ], // referenca na gornji objekt grupe
ami: "ami-c55673a0" // AMI za us-east-2 (Ohio),
userData: userData // pokreće jednostavni web poslužitelj
});
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;
Ovo je osnovni program Pulumi: jednostavno alocira sigurnosnu grupu EC2 i instancu. Međutim, valja napomenuti da ovdje kršimo sva tri pravila navedena gore. Idemo pisati testove!
Pišemo testove
Opća struktura naših testova izgledati će kao uobičajeni Mocha testovi:
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): Treba imati oznaku Name.
// TODO(check 2): Ne smije biti inline-skripte userData.
});
let group = infra.group;
describe("#group", function() {
// TODO(check 3): Ne smije biti SSH-a otvorenog za internet.
});
}); Sada idemo napisati naš prvi test: uvjerimo se da instanci imaju oznaku Name. Za provjeru toga jednostavno dobijemo objekt EC2 instance i provjerimo odgovarajuću svojstvo 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();
}
});
});Izgleda kao običan test, ali sa nekoliko značajnih osobina koje zaslužuju pažnju:
- Budući da tražimo stanje resursa pre implementacije, naši testovi se uvek izvode u režimu „plan“ (ili „preview“). Tako postoji mnogo svojstava čije vrednosti jednostavno neće biti dobijene ili će biti neodređene. Ovo uključuje sve izlazne osobine koje izračunava vaš provajder u oblaku. Za naše testove to je u redu — proveravamo samo ulaze. O ovom pitanju ćemo se ponovo osvrnuti kasnije, kada dođemo do integracionih testova.
- Budući da su sva svojstva Pulumi resursa „izlazi“, i mnogi od njih se izračunavaju asinhrono, treba da koristimo metodu apply da bismo pristupili vrednostima. Ovo je veoma slično promenljivama i funkcijama.
then. - Budući da koristimo nekoliko svojstava za prikaz URN resursa u poruci o grešci, potrebno je da koristimo funkciju
pulumi.all, kako bismo ih spojili. - Na kraju, budući da se ove vrednosti izračunavaju asinhrono, potrebno je da koristimo ugrađenu asinhronu mogućnost Mocha sa povratnim pozivom
završenoili vraćanjem promenljive.
Kada sve postavimo, imamo pristup ulaznim podacima kao jednostavnim JavaScript vrednostima. Osoba tags je mapa (asocijativni niz), tako da ćemo samo proveriti da je (1) ne false, i (2) da postoji ključ za Name. To je vrlo jednostavno i sada možemo proveriti sve što poželimo!
Sada hajde da napišemo naš drugi test. Ovo je još jednostavnije:
// 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();
}
});
});I, na kraju, napišimo treći test. Ovo će biti malo složenije, jer tražimo pravila ulaska vezana za grupu bezbednosti, kojih može biti mnogo, kao i CIDR opsege u tim pravilima, kojih takođe može biti mnogo. Ali mi smo to uspeli:
// 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 to. Sada hajde da pokrenemo testove!
Pokretanje testova
Testove možete pokrenuti na uobičajen način, koristeći vaš odabrani okvir za testiranje. Ali postoji jedna osobina Pulumi koju vredi naglasiti.
Obično se za pokretanje Pulumi programa koristi pulumi CLI (Command Line Interface), koji konfigurira runtime jezika, kontrolira pokretanje Pulumi motora kako bi se mogle zabilježiti operacije s resursima i uključiti ih u plan itd. Međutim, postoji jedan problem. Kada se pokreće pod kontrolom vašeg testnog okvira, neće biti veze između CLI-a i Pulumi motora.
Da bismo zaobišli ovaj problem, jednostavno trebamo navesti sljedeće:
- Ime projekta koje se nalazi u varijabli okruženja
PULUMI_NODEJS_PROJECT(ili, u općem slučaju,PULUMI__PROJECT za ostale jezike).
Ime steka koje je navedeno u varijabli okruženjaPULUMI_NODEJS_STACK(ili, u općem slučaju,PULUMI__STACK).
Vaše varijable konfiguracije steka. Mogu se dobiti pomoću varijable okruženjaPULUMI_CONFIGi njihov format predstavlja JSON mapu s parovima ključ/vrijednost.Program će ispisati upozorenja koja govore da tijekom izvođenja nije dostupna veza s CLI/motorom. To je važno, jer zapravo vaša aplikacija neće ništa raspoređivati i to može biti iznenađenje ako to nije ono što ste htjeli učiniti! Da biste rekli Pulumi-u da je to upravo ono što trebate, možete postaviti
PULUMI_TEST_MODEutrue.Zamislite da trebamo navesti naziv projekta u
my-ws, naziv stekadev, i AWS regijuus-west-2. Komandna linija za izvođenje Mocha testova izgledat će ovako:$ PULUMI_TEST_MODE=true PULUMI_NODEJS_STACK="my-ws" PULUMI_NODEJS_PROJECT="dev" PULUMI_CONFIG='{ "aws:region": "us-west-2" }' mocha tests.jsIzvršavanje ovoga, kako je i očekivano, pokazat će nam da imamo tri neuspjela testa!
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 groupHajde da ispravimo naš 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 ], // referenca na objekt grupe iznad ami: "ami-c55673a0" // AMI za us-east-2 (Ohio), }); exports.group = group; exports.server = server; exports.publicIp = server.publicIp; exports.publicHostName = server.publicDns;A zatim ponovo pokrenemo testove:
Infrastruktura #server ✓ mora imati oznaku imena ✓ ne smije koristiti userData (umjesto toga koristite AMI) #group ✓ ne smije otvoriti port 22 (SSH) za Internet 3 prolazna (16ms)Sve je prošlo uspješno… Hura! ✓✓✓
Danas je to sve, a o testiranju implementacije razgovarat ćemo u drugom dijelu prijevoda 😉
Izvor: habr.com
