Selamat siang teman teman. Untuk mengantisipasi dimulainya aliran baru pada tingkat tersebut
Menggunakan Pulumi dan bahasa pemrograman tujuan umum untuk kode infrastruktur (Infrastruktur sebagai Kode) memberikan banyak keuntungan: ketersediaan keterampilan dan pengetahuan, penghapusan boilerplate dalam kode melalui abstraksi, alat yang familiar bagi tim Anda, seperti IDE dan linter. Semua alat rekayasa perangkat lunak ini tidak hanya membuat kita lebih produktif, namun juga meningkatkan kualitas kode kita. Oleh karena itu, wajar jika penggunaan bahasa pemrograman tujuan umum memungkinkan kita memperkenalkan praktik pengembangan perangkat lunak penting lainnya - pengujian.
Dalam artikel ini, kita akan melihat bagaimana Pulumi membantu kita menguji infrastruktur sebagai kode.
Mengapa menguji infrastruktur?
Sebelum membahas secara rinci, ada baiknya mengajukan pertanyaan: “Mengapa menguji infrastruktur?” Ada banyak alasan untuk hal ini dan berikut beberapa di antaranya:
- Pengujian unit fungsi individual atau fragmen logika program Anda
- Memverifikasi keadaan infrastruktur yang diinginkan terhadap batasan tertentu.
- Deteksi kesalahan umum, seperti kurangnya enkripsi pada keranjang penyimpanan atau akses terbuka yang tidak terlindungi dari Internet ke mesin virtual.
- Memeriksa pelaksanaan penyediaan infrastruktur.
- Melakukan pengujian runtime logika aplikasi yang berjalan di dalam infrastruktur "terprogram" Anda untuk memeriksa fungsionalitas setelah penyediaan.
- Seperti yang bisa kita lihat, ada beragam pilihan pengujian infrastruktur. Polumi memiliki mekanisme pengujian di setiap titik pada spektrum ini. Mari kita mulai dan lihat cara kerjanya.
Pengujian satuan
Program Pulumi ditulis dalam bahasa pemrograman tujuan umum seperti JavaScript, Python, TypeScript atau Go. Oleh karena itu, kekuatan penuh dari bahasa-bahasa ini, termasuk alat dan perpustakaannya, termasuk kerangka pengujian, tersedia untuk mereka. Pulumi bersifat multi-cloud, artinya dapat digunakan untuk pengujian dari penyedia cloud mana pun.
(Dalam artikel ini, meskipun multibahasa dan multicloud, kami menggunakan JavaScript dan Mocha dan fokus pada AWS. Anda dapat menggunakan Python unittest
, Go test framework, atau framework pengujian lainnya yang Anda suka. Dan, tentu saja, Pulumi berfungsi baik dengan Azure, Google Cloud, Kubernetes.)
Seperti yang telah kita lihat, ada beberapa alasan mengapa Anda mungkin ingin menguji kode infrastruktur Anda. Salah satunya adalah pengujian unit konvensional. Karena kode Anda mungkin memiliki fungsi - misalnya, untuk menghitung CIDR, menghitung nama, tag secara dinamis, dll. - Anda mungkin ingin mengujinya. Ini sama dengan menulis pengujian unit reguler untuk aplikasi dalam bahasa pemrograman favorit Anda.
Untuk lebih rumitnya, Anda dapat memeriksa bagaimana program Anda mengalokasikan sumber daya. Sebagai ilustrasi, bayangkan kita perlu membuat server EC2 sederhana dan kita ingin memastikan hal-hal berikut:
- Instans memiliki tag
Name
. - Instance tidak boleh menggunakan skrip inline
userData
- kita harus menggunakan AMI (gambar). - Seharusnya tidak ada SSH yang terekspos ke Internet.
Contoh ini didasarkan pada
indeks.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;
Ini adalah program dasar Pulumi: program ini hanya mengalokasikan grup keamanan EC2 dan sebuah instans. Namun, perlu dicatat bahwa di sini kita melanggar ketiga aturan di atas. Ayo menulis tes!
Tes menulis
Struktur umum pengujian kami akan terlihat seperti pengujian Mocha biasa:
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, открытого в Интернет.
});
});
Sekarang mari kita tulis pengujian pertama kita: pastikan instance tersebut memiliki tag Name
. Untuk memeriksanya kita cukup mendapatkan objek instance EC2 dan memeriksa properti yang sesuai 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();
}
});
});
Ini terlihat seperti tes biasa, tetapi dengan beberapa fitur yang perlu diperhatikan:
- Karena kami menanyakan status sumber daya sebelum penerapan, pengujian kami selalu dijalankan dalam mode “rencana” (atau “pratinjau”). Jadi, ada banyak properti yang nilainya tidak dapat diambil atau ditentukan. Ini mencakup semua properti keluaran yang dihitung oleh penyedia cloud Anda. Ini normal untuk pengujian kami - kami hanya memeriksa data masukan. Kami akan kembali ke masalah ini nanti, terkait pengujian integrasi.
- Karena semua properti sumber daya Pulumi adalah keluaran, dan banyak di antaranya dievaluasi secara asinkron, kita perlu menggunakan metode apply untuk mengakses nilainya. Ini sangat mirip dengan janji dan fungsi
then
. - Karena kita menggunakan beberapa properti untuk menampilkan URN sumber daya dalam pesan kesalahan, kita perlu menggunakan fungsi tersebut
pulumi.all
untuk menggabungkannya. - Terakhir, karena nilai-nilai ini dihitung secara asinkron, kita perlu menggunakan fitur panggilan balik asinkron bawaan Mocha
done
atau mengembalikan janji.
Setelah kami menyiapkan semuanya, kami akan memiliki akses ke input sebagai nilai JavaScript sederhana. Properti tags
adalah peta (array asosiatif), jadi kami pastikan saja (1) tidak salah, dan (2) ada kunci untuk Name
. Ini sangat sederhana dan sekarang kita bisa menguji apa saja!
Sekarang mari kita tulis cek kedua kita. Ini bahkan lebih sederhana:
// 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();
}
});
});
Dan terakhir, mari kita menulis tes ketiga. Ini akan menjadi sedikit lebih rumit karena kita mencari aturan login yang terkait dengan grup keamanan, yang jumlahnya bisa banyak, dan rentang CIDR dalam aturan tersebut, yang juga bisa banyak. Tapi kami berhasil:
// 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();
}
});
});
Itu saja. Sekarang mari kita jalankan tesnya!
Menjalankan tes
Dalam kebanyakan kasus, Anda dapat menjalankan pengujian dengan cara biasa, menggunakan kerangka pengujian pilihan Anda. Namun ada satu fitur Pulumi yang patut diperhatikan.
Biasanya, untuk menjalankan program Pulumi, CLI (antarmuka Baris Perintah) pulimi digunakan, yang mengonfigurasi runtime bahasa, mengontrol peluncuran mesin Pulumi sehingga operasi dengan sumber daya dapat direkam dan disertakan dalam rencana, dll. Namun, ada satu masalah. Saat berjalan di bawah kendali kerangka pengujian Anda, tidak akan ada komunikasi antara CLI dan mesin Pulumi.
Untuk mengatasi masalah ini, kita hanya perlu menentukan hal berikut:
- Nama proyek, yang terdapat dalam variabel lingkungan
PULUMI_NODEJS_PROJECT
(atau, lebih umum lagi,PULUMI__PROJECT для других языков).
Nama tumpukan yang ditentukan dalam variabel lingkunganPULUMI_NODEJS_STACK
(atau, lebih umum lagi,PULUMI__ STACK).
Variabel konfigurasi tumpukan Anda. Mereka dapat diperoleh dengan menggunakan variabel lingkunganPULUMI_CONFIG
dan formatnya adalah peta JSON dengan pasangan kunci/nilai.Program akan mengeluarkan peringatan yang menunjukkan bahwa koneksi ke CLI/mesin tidak tersedia selama eksekusi. Hal ini penting karena program Anda tidak akan benar-benar menerapkan apa pun dan mungkin akan mengejutkan jika Anda tidak ingin melakukan hal tersebut! Untuk memberi tahu Pulumi bahwa inilah yang Anda perlukan, Anda dapat menginstal
PULUMI_TEST_MODE
вtrue
.Bayangkan kita perlu menentukan nama proyek di
my-ws
, nama tumpukandev
, dan Wilayah AWSus-west-2
. Baris perintah untuk menjalankan tes Mocha akan terlihat seperti ini:$ PULUMI_TEST_MODE=true PULUMI_NODEJS_STACK="my-ws" PULUMI_NODEJS_PROJECT="dev" PULUMI_CONFIG='{ "aws:region": "us-west-2" }' mocha tests.js
Melakukan hal ini, seperti yang diharapkan, akan menunjukkan kepada kita bahwa kita memiliki tiga pengujian yang gagal!
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
Mari kita perbaiki program kita:
"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;
Dan kemudian jalankan tes lagi:
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)
Semuanya berjalan baik... Hore! ✓✓✓
Itu saja untuk hari ini, tapi kita akan membahas tentang pengujian penerapan di bagian kedua terjemahan 😉
Sumber: www.habr.com