Përshëndetje, miq. Para fillimit të një pjesë të re në kursin po ndajem me ju një përkthim të ri. Le të fillojmë.

Përdorimi i Pulumi dhe gjuhëve të programimit të përgjithshme për kodin e nëfrastrukturës (Infrastructure as Code) ofron shumë përparësi: njohuri dhe aftësi, eliminimin e boilerplate-it në kod përmes abstraksionit, mjete të njohura për ekipin tuaj si IDE dhe linters. Të gjitha këto mjete inxhinierie softuerike jo vetëm që na bëjnë më produktivë, por gjithashtu përmirësojnë cilësinë e kodit. Prandaj, është krejt natyrale që përdorimi i gjuhëve të programimit të përgjithshme lejon miratimin e një praktike tjetër të rëndësishme të zhvillimit të softuerit — testimin.
Në këtë artikull do të shqyrtojmë si Pulumi ndihmon në testimin e «infrastrukturës si kod».

Pse të testojmë infrastrukturën?
Para se të hyjmë në detaje, ia vlen të bëjmë pyetje: «Pse duhet të testojmë infrastrukturën?» Ka shumë arsye për këtë dhe këtu janë disa prej tyre:
- Testimi modular i funksioneve të ndryshme ose fragmenteve të logjikës së programit tuaj
- Kontrolli i gjendjes së dëshiruar të infrastrukturës për t'iu përmbajtur disa kufizimeve.
- Zbulimi i gabimeve të zakonshme, si mungesa e enkriptimit në storage bucket ose qasje e pa sigurt dhe e hapur nga Interneti në makinat virtuale.
- Kontrolli i përfundimit të provizionit të infrastrukturës.
- Kryerja e testeve runtime të logjikës së aplikacionit që ekzekutohet brenda infrastrukturës suaj «të programuar» për të kontrolluar funksionalitetin pas provizionit.
- Siç e shohim, ka një gamë të gjerë mundësish për testimin e infrastrukturës. Në Polumi ka mekanizma për testimin në çdo pikë të kësaj game. Le të fillojmë dhe të shohim si funksionon.
Testimi modular
Programet Pulumi krijohen në gjuhët e programimit të përgjithshme, si JavaScript, Python, TypeScript ose Go. Prandaj, ato kanë në dispozicion të gjithë potencialin e këtyre gjuhëve, duke përfshirë mjetet dhe bibliotekat e tyre, përfshirë edhe kuadrin e testeve. Pulumi është multi-cloud, që do të thotë se mund të përdoren çdo ofrues cloud për testet.
(Në këtë artikull, përkundër multilinguizmit dhe multi-cloud-it, ne përdorim JavaScript dhe Mocha dhe orientohemi ndaj AWS. Mund të përdoret Python unittest,.Frameworkun testimin Go ose çfarëdo tjetër që ju pëlqen. Dhe, sigurisht, Pulumi funksionon shumë mirë me Azure, Google Cloud, Kubernetes.)
Siç e pamë, ka disa arsye pse mund t'ju nevojitet të testoni kodin tuaj të infrastrukturës. Njëra nga to është testimi standart modular. Duke qenë se kodi juaj mund të ketë funksione - për shembull, për të llogaritur CIDR, për të llogaritur emrat, etiketat etj. - ndoshta do të donit t'i testonit ato. Kjo është e njëjtë si të shkruani teste standart modulare për aplikacione në gjuhën tuaj të preferuar të programimit.
Nëse e komplikohem disi, mund të kontrolloni se si programi juaj shpërndan burimet. Për të ilustruar, le të imagjinojmë se na nevojitet të krijojmë një server të thjeshtë EC2 dhe dëshirojmë të jemi të sigurt për sa vijon:
- Instancat kanë një etiketë
Emri. - Instancat nuk duhet të përdorin skripte inline
userData– duhet të përdorim AMI (imazhi). - Nuk duhet të ketë SSH të hapur në Internet.
Ky shembull është shkruar mbi bazën e :
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 ], // referencuar objektin e grupit më sipër
ami: "ami-c55673a0" // AMI për ne-east-2 (Ohio),
userData: userData // filloni një server të thjeshtë web
});
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;
Kjo është një program basic Pulumi: ajo thjesht alokoton një grup sigurie EC2 dhe një instancë. Megjithatë, duhen vënë re se këtu po shkelim të tri rregullat e përmendura më sipër. Le të fillojmë të shkruajmë teste!
Le të shkruajmë teste
Struktura e përgjithshme e testeve tona do të duket si testet standarde të Mocha:
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): Duhet të ketë një etiketë emri.
// TODO(check 2): Nuk duhet të ketë skripte inline userData.
});
let group = infra.group;
describe("#group", function() {
// TODO(check 3): Nuk duhet të ketë SSH të hapur në Internet.
});
}); Tani le të shkruajmë testin tonë të parë: të sigurohemi që instancat të kenë një etiketë Emri. Për ta verifikuar këtë thjesht marrim objektin e instancës EC2 dhe kontrollojmë pronën përkatëse : ngarkesë. Mund të përdoren etika të tjera kuptimplote. Ato caktohen:
// 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();
}
});
});Duket si një test i zakonshëm, por me disa veçori që meritojnë vëmendje:
- Pasi kërkojmë gjendjen e burimit para se të desplojmë, testet tona gjithmonë kryhen në modin "plan" (ose "preview"). Kështu, ka shumë pronësi, vlerat e të cilave thjesht nuk do të merren ose do të mbeten të paqartë. Këtu përfshihen të gjitha pronësitë dalëse që llogariten nga ofruesi juaj i cloud. Për testet tona kjo është në rregull — ne kontrollojmë vetëm të dhënat hyrëse. Në këtë çështje do të kthehemi më vonë, kur të arrijmë te testet integruese.
- Duke qenë se të gjitha pronësitë e burimeve Pulumi janë "dalëse" dhe shumë prej tyre llogariten asinkronisht, na nevojitet të përdorim metodën apply për të aksesuar vlerat. Kjo është shumë e ngjashme me premtimet dhe një funksion tjetër.
then. - Pasi përdorim disa pronësi për të treguar URN e burimit në mesazhin e gabimit, na nevojitet të përdorim funksionin
pulumi.all, për t'i bashkuar ato. - Në fund, pasi këto vlera llogariten asinkronisht, na nevojitet përdorimi i mundësisë asinkrone të ndërtuar në Mocha me një kthim të thirrjes
doneapo kthimin e premtimit.
Pasi të gjithçka të jetë e vendosur, do të kemi akses në të dhënat hyrëse si vlera të thjeshta JavaScript. Pronësia : ngarkesë. Mund të përdoren etika të tjera kuptimplote. Ato caktohen është një map (në një asociacion), prandaj thjesht do të sigurohemi që (1) ajo të mos jetë false, dhe (2) të ketë një çelës për Emri. Kjo është shumë e thjeshtë dhe tani mund të kontrollojmë gjithçka që duam!
Tani le të shkruajmë kontrollin tonë të dytë. Kjo është edhe më e thjeshtë:
// 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();
}
});
});Dhe, përfundimisht, le të shkruajmë testin e tretë. Kjo do të jetë pak më e komplikuar, sepse po kërkojmë rregulla hyrëse të lidhura me grupin e sigurisë, të cilat mund të kenë shumë dhe gamat CIDR në këto rregulla, gjithashtu shumë. Por e përballëm:
// 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();
}
});
});Kaq ishte gjithçka. Tani le të ekzekutojmë testet!
Ekzekutimi i testeve
Ekzekutimi i testeve, në shumicën e rasteve, mund të bëhet në mënyrë të zakonshme, duke përdorur kornizën e testeve që keni zgjedhur. Por ka një veçori të Pulumi që duhet t'i kushtoni vëmendje.
Zak一般pulimi CLI (Интерфейс командной строки) используется për të nisur programet Pulumi, i cili vendos runtime-in e gjuhës, kontrollon lançimet e motorit Pulumi, në mënyrë që të mund të fiksosh operacionet me burimet dhe t'i përfshijë ato në plan, etj. Megjithatë, ka një problem. Gjatë ekzekutimit nën kontrollin e kuadrit tuaj të testit, nuk do të ketë një lidhje midis CLI dhe motorit Pulumi.
Për ta zgjidhur këtë problem, ne thjesht duhet të specifikojmë të following:
- Emri i projektit, i cili ndodhet në variablën e mjedisit
PULUMI_NODEJS_PROJECT(ose, në një rast më të përgjithshëm,PULUMI__PROJECT për gjuhë të tjera).
Emri i stackut, i cili është i specifikuar në variablën e mjedisitPULUMI_NODEJS_STACK(ose, në një rast më të përgjithshëm,PULUMI__ STACK).
Variablat e konfiguruara të stackut tuaj. Ata mund të merren përmes variablës së mjedisitPULUMI_CONFIGdhe formati i tyre është një hartë JSON me çifte çelës / vlerë.Programi do të japë paralajmërime që tregojnë se gjatë ekzekutimit nuk është në dispozicion një lidhje me CLI / engine. Kjo është e rëndësishme, sepse në të vërtetë, programi juaj nuk do të shtrijë asgjë dhe kjo mund të jetë një surprizë nëse nuk është ajo që dëshirosh të bësh! Për t'i thënë Pulumi se kjo është ajo që duhet, mund të vendosni
PULUMI_TEST_MODEnëtrue.Imagjinoni se na nevojitet të specifikojmë emrin e projektit në
my-ws, emri i stackutdev, dhe rajoni AWSus-west-2. Komanda në linjë për të ekzekutuar testet e Mocha do të duket si më poshtë:$ PULUMI_TEST_MODE=true PULUMI_NODEJS_STACK="my-ws" PULUMI_NODEJS_PROJECT="dev" PULUMI_CONFIG='{ "aws:region": "us-west-2" }' mocha tests.jsEkzekutimi i kësaj, siç pritej, do të tregojë se kemi tre teste të dështuar!
Infrastrukturë #server 1) duhet të ketë një etiketë emri 2) nuk duhet të përdorë userData (përdor një AMI në vend) #group 3) nuk duhet të hapë portin 22 (SSH) për Internetin 0 e kaluara (17ms) 3 të dështuara 1) Infrastrukturë #server duhet të ketë një etiketë emri: Gabim: Mungon një etiketë emri në server urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www 2) Infrastrukturë #server nuk duhet të përdorë userData (përdor një AMI në vend): Gabim: Përdorim i paligjshëm i userData në server urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www 3) Infrastrukturë #group nuk duhet të hapë portin 22 (SSH) për Internetin: Gabim: Porti 22 SSH i hapur për Internetin (CIDR 0.0.0.0/0) në grupLe të rregullojmë programin tonë:
"përdorni strikt"; 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 ], // referenconi objektin e grupit më sipër ami: "ami-c55673a0" // AMI për us-east-2 (Ohio), }); exports.group = group; exports.server = server; exports.publicIp = server.publicIp; exports.publicHostName = server.publicDns;Dhe pastaj ta riplotësojmë testin:
Infrastruktura #server ✓ duhet të ketë një etiketë emri ✓ nuk duhet të përdorë userData (përdorni një AMI në vend) #group ✓ nuk duhet të hapë portin 22 (SSH) për internetin 3 kalime (16ms)E gjithë kjo përfundoi me sukses… Hurra! ✓✓✓
Kjo është gjithçka për sot, dhe për testimin e shpërndarjes do të flasim në pjesën e dytë të përkthimit 😉
Burimi: habr.com
