Menguji infrastruktur Anda sebagai kode dengan Pulumi. Bagian 1

Selamat siang teman Untuk mengantisipasi dimulainya aliran baru pada kursus "DevOps Practices and Tools" kami membagikan terjemahan baru kepada Anda. Ayo pergi.



Menggunakan Pulumi dan bahasa pemrograman untuk keperluan umum untuk Infrastruktur sebagai Kode memberikan banyak keuntungan: memiliki keterampilan dan pengetahuan, menghilangkan boilerplate dalam kode melalui abstraksi, alat yang familier bagi tim Anda, seperti IDE dan linter. Semua alat rekayasa perangkat lunak ini tidak hanya membuat kita lebih produktif, tetapi juga meningkatkan kualitas kode. Oleh karena itu, wajar jika penggunaan bahasa pemrograman untuk tujuan umum memungkinkan Anda untuk memperkenalkan praktik penting lainnya dalam pengembangan perangkat lunak - pengujian .

Pada artikel ini, kita akan melihat bagaimana Pulumi membantu menguji "infrastruktur sebagai kode" kami.



Mengapa menguji infrastruktur?


Sebelum membahas detail, ada baiknya mengajukan pertanyaan: "Mengapa kita perlu menguji infrastruktur sama sekali?" Ada banyak alasan untuk ini, dan inilah beberapa di antaranya:

  • Unit menguji fungsi individu atau potongan-potongan logika dalam program Anda
  • Periksa kondisi infrastruktur yang diinginkan untuk kepatuhan dengan batasan tertentu.
  • Deteksi kesalahan umum, seperti kurangnya enkripsi atau penyimpanan tidak aman, membuka akses dari Internet ke mesin virtual.
  • Verifikasi penyediaan infrastruktur.
  • Melakukan pengujian runtime terhadap logika aplikasi yang berjalan di dalam infrastruktur "terprogram" Anda untuk memeriksa kesehatan setelah penyediaan.
  • Seperti yang dapat kita lihat, ada berbagai pilihan pengujian infrastruktur. Polumi memiliki mekanisme pengujian di setiap titik dalam spektrum ini. Mari kita mulai dan melihat cara kerjanya.

Pengujian unit


Program Pulumi dibuat dalam bahasa pemrograman untuk tujuan umum seperti JavaScript, Python, TypeScript, atau Go. Oleh karena itu, kekuatan penuh dari bahasa ini tersedia untuk mereka, termasuk alat dan pustaka mereka, termasuk kerangka kerja pengujian. Pulumi adalah multi-cloud, yang berarti kemampuan untuk menggunakan penyedia cloud apa saja untuk pengujian.

(Dalam artikel ini, meskipun multi-bahasa dan multi-cloud, kami menggunakan JavaScript dan Mocha dan fokus pada AWS. Anda dapat menggunakan Python unittest , kerangka uji Go atau kerangka uji lain yang Anda suka. Dan, tentu saja, Pulumi bekerja sangat baik dengan Azure, Google Cloud, Kubernet.)

Seperti yang telah kita lihat, ada beberapa alasan mengapa Anda mungkin perlu menguji kode infrastruktur Anda. Salah satunya adalah unit testing yang biasa. Karena kode Anda mungkin memiliki fungsi - misalnya, untuk menghitung CIDR, secara dinamis menghitung nama, tag, dll. - Anda mungkin ingin menguji mereka. Ini sama dengan menulis tes unit reguler untuk aplikasi dalam bahasa pemrograman favorit Anda.
Jika Anda sedikit menyulitkan, Anda dapat memeriksa bagaimana program Anda mengalokasikan sumber daya. Untuk mengilustrasikannya, mari kita bayangkan bahwa kita perlu membuat server EC2 sederhana dan kami ingin memastikan hal-hal berikut:

  • Instances memiliki tag Name .
  • Instans tidak boleh menggunakan skrip inline userData - kita harus menggunakan AMI (gambar).
  • Seharusnya tidak ada SSH terbuka di Internet.

Contoh ini ditulis berdasarkan contoh aws-js-webserver saya :

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; 

Ini adalah program Pulumi dasar: ini hanya mengalokasikan grup keamanan EC2 dan instance. Namun, perlu dicatat bahwa di sini kita melanggar ketiga aturan yang disebutkan di atas. Mari kita menulis tes!

Tes menulis


Struktur umum tes kami akan terlihat seperti tes 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 tes pertama kami: pastikan instance memiliki tag Name . Untuk memverifikasi ini, kita cukup mendapatkan objek instance EC2 dan memeriksa properti tags sesuai:

  // 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 patut diperhatikan:

  • Karena kami meminta status sumber daya sebelum penyebaran, pengujian kami selalu dijalankan dalam mode "plan" (atau "preview"). Dengan demikian, ada banyak properti yang nilainya tidak akan diterima atau tidak akan ditentukan. Ini termasuk semua properti keluaran yang dihitung penyedia cloud Anda. Untuk pengujian kami, ini normal - kami hanya memeriksa data input. Kami akan kembali ke masalah ini nanti ketika datang ke tes integrasi.
  • Karena semua properti dari sumber daya Pulumi adalah "output", dan banyak dari mereka yang dihitung secara serempak, kita perlu menggunakan metode yang berlaku untuk mengakses nilai. Ini sangat mirip dengan janji dan then .
  • Karena kami menggunakan beberapa properti untuk menampilkan URN sumber daya dalam pesan kesalahan, kami perlu menggunakan fungsi pulumi.all untuk menggabungkannya.
  • Akhirnya, karena nilai-nilai ini dihitung secara tidak serempak, kita perlu menggunakan fitur asinkron bawaan Mocha dengan panggilan balik yang done atau janji pengembalian.

Setelah kami mengonfigurasi semuanya, kami akan memiliki akses ke data input sebagai nilai JavaScript sederhana. Properti tags adalah peta (array asosiatif), jadi kami hanya memastikan bahwa itu (1) tidak salah, dan (2) ada kunci untuk Name . Ini sangat sederhana dan sekarang kita dapat memeriksa apa pun!

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 akhirnya, kami akan menulis tes ketiga. Ini akan menjadi sedikit lebih rumit karena kami mencari aturan masuk yang terkait dengan grup keamanan, yang mungkin banyak, dan rentang CIDR dalam aturan ini, yang mungkin juga 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 tes!

Menjalankan tes


Dalam kebanyakan kasus, Anda dapat menjalankan tes dengan cara biasa menggunakan kerangka uji pilihan Anda. Tetapi ada satu fitur Pulumi yang harus Anda perhatikan.
Biasanya, Pulimi CLI (antarmuka Baris Perintah, antarmuka baris perintah) digunakan untuk memulai program Pulumi, yang mengatur runtime bahasa, mengontrol mesin Pulumi dimulai, sehingga dimungkinkan untuk merekam operasi dengan sumber daya dan memasukkannya ke dalam rencana, dll. Namun, ada satu masalah. Ketika diluncurkan di bawah kendali kerangka pengujian Anda, tidak akan ada koneksi antara CLI dan mesin Pulumi.

Untuk mengatasi masalah ini, kita hanya perlu menentukan yang berikut:

  • Nama proyek, yang terkandung dalam variabel lingkungan PULUMI_NODEJS_PROJECT (atau, lebih umum, PULUMI__PROJECT ).
    Nama tumpukan yang ditentukan dalam variabel lingkungan PULUMI_NODEJS_STACK (atau, lebih umum, PULUMI__ STACK).
    Variabel konfigurasi tumpukan Anda. Mereka dapat diperoleh menggunakan PULUMI_CONFIG lingkungan PULUMI_CONFIG dan formatnya adalah peta JSON dengan pasangan kunci / nilai.

    Program akan mengeluarkan peringatan yang menunjukkan bahwa pada saat dijalankan koneksi ke CLI / engine tidak tersedia. Ini penting, karena pada kenyataannya, program Anda tidak akan menyebarkan apa pun dan ini mungkin mengejutkan jika ini bukan yang Anda inginkan! Untuk memberi tahu Pulumi bahwa ini persis yang Anda butuhkan, Anda dapat menetapkan PULUMI_TEST_MODE menjadi true .

    Bayangkan kita perlu menentukan nama proyek di my-ws , nama stack dev , dan wilayah AWS us-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 ini, seperti yang diharapkan, akan menunjukkan kepada kita bahwa kita memiliki tiga ujian jatuh!

     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 kami:

     "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 kembali tes:

     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 dengan baik ... Hore! ✓ ✓ ✓

    Itu saja untuk hari ini, tetapi kita akan berbicara tentang menguji penyebaran di bagian kedua terjemahan ;-)

Source: https://habr.com/ru/post/id463001/


All Articles