Pulumi ile Altyapının Kod Olarak Test Edilmesi. Bölüm 1

Tünaydın arkadaşlar. Oranda yeni bir akışın başlaması beklentisiyle "DevOps uygulamaları ve araçları" Yeni bir çeviriyi sizlerle paylaşıyoruz. Gitmek.

Pulumi ile Altyapının Kod Olarak Test Edilmesi. Bölüm 1

Altyapı kodu için Pulumi ve genel amaçlı programlama dillerinin kullanılması (Kod Olarak Altyapı) birçok avantaj sağlar: beceri ve bilginin kullanılabilirliği, soyutlama yoluyla koddaki standartların ortadan kaldırılması, IDE'ler ve linterler gibi ekibinizin aşina olduğu araçlar. Tüm bu yazılım mühendisliği araçları bizi yalnızca daha üretken kılmakla kalmıyor, aynı zamanda kodumuzun kalitesini de artırıyor. Bu nedenle, genel amaçlı programlama dillerinin kullanımının başka bir önemli yazılım geliştirme uygulamasını tanıtmamıza olanak sağlaması doğaldır - test.

Bu makalede Pulumi'nin kod olarak altyapımızı test etmemize nasıl yardımcı olduğuna bakacağız.

Pulumi ile Altyapının Kod Olarak Test Edilmesi. Bölüm 1

Neden altyapıyı test etmelisiniz?

Detaylara girmeden önce şu soruyu sormakta fayda var: “Neden altyapıyı test ediyorsunuz?” Bunun birçok nedeni var ve işte bunlardan bazıları:

  • Program mantığınızın bireysel işlevlerinin veya parçalarının birim testi
  • Belirli kısıtlamalara göre altyapının istenen durumunu doğrular.
  • Depolama paketinin şifrelenmemesi veya İnternetten sanal makinelere korumasız, açık erişim gibi yaygın hataların tespiti.
  • Altyapı tedarikinin uygulanmasının kontrol edilmesi.
  • Sağlama sonrasında işlevselliği kontrol etmek için "programlanmış" altyapınız içinde çalışan uygulama mantığının çalışma zamanı testini gerçekleştirme.
  • Gördüğümüz gibi çok çeşitli altyapı test seçenekleri var. Polumi'nin bu spektrumun her noktasında test yapma mekanizmaları vardır. Hadi başlayalım ve nasıl çalıştığını görelim.

Birim testi

Pulumi programları JavaScript, Python, TypeScript veya Go gibi genel amaçlı programlama dillerinde yazılmıştır. Bu nedenle, test çerçeveleri de dahil olmak üzere araçları ve kütüphaneleri de dahil olmak üzere bu dillerin tüm gücü onların kullanımına açıktır. Pulumi çoklu buluttur, yani herhangi bir bulut sağlayıcısından test yapmak için kullanılabilir.

(Bu yazımızda çok dilli ve çoklu bulut olmasına rağmen JavaScript ve Mocha kullanıyoruz ve AWS’ye odaklanıyoruz. Python kullanabilirsiniz. unittest, Go test çerçevesi veya beğendiğiniz başka bir test çerçevesi. Ve elbette Pulumi, Azure, Google Cloud ve Kubernetes ile harika çalışıyor.)

Gördüğümüz gibi altyapı kodunuzu test etmek isteyebileceğiniz çeşitli nedenler var. Bunlardan biri geleneksel birim testidir. Çünkü kodunuzun CIDR'yi hesaplamak, adları, etiketleri vb. dinamik olarak hesaplamak gibi işlevleri olabilir. - muhtemelen onları test etmek isteyeceksiniz. Bu, favori programlama dilinizdeki uygulamalar için düzenli birim testleri yazmakla aynıdır.
Biraz daha karmaşık hale getirmek için programınızın kaynakları nasıl tahsis ettiğini kontrol edebilirsiniz. Örnek vermek gerekirse, basit bir EC2 sunucusu oluşturmamız gerektiğini ve aşağıdakilerden emin olmak istediğimizi düşünelim:

  • Örneklerin bir etiketi var Name.
  • Örnekler satır içi komut dosyası kullanmamalıdır userData - bir AMI (resim) kullanmalıyız.
  • İnternete açık hiçbir SSH olmamalıdır.

Bu örnek dayanmaktadır benim örneğim aws-js-web sunucusu:

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;

Bu, temel Pulumi programıdır: basitçe bir EC2 güvenlik grubu ve bir örnek tahsis eder. Ancak burada yukarıda belirtilen üç kuralı da ihlal ettiğimizi belirtmek gerekir. Hadi testler yazalım!

Test yazma

Testlerimizin genel yapısı normal Mocha testlerine benzeyecektir:

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, открытого в Интернет.
    });
});

Şimdi ilk testimizi yazalım: örneklerin etiketine sahip olduğundan emin olun Name. Bunu kontrol etmek için EC2 örnek nesnesini alıp ilgili özelliği kontrol etmemiz yeterlidir. 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();
                }
            });
        });

Normal bir teste benziyor ancak dikkate değer birkaç özelliği var:

  • Dağıtımdan önce bir kaynağın durumunu sorguladığımız için testlerimiz her zaman "plan" (veya "önizleme") modunda çalıştırılır. Dolayısıyla değerleri alınamayacak veya tanımlanamayacak birçok özellik vardır. Buna, bulut sağlayıcınız tarafından hesaplanan tüm çıktı özellikleri dahildir. Testlerimiz için bu normaldir; yalnızca giriş verilerini kontrol ederiz. Entegrasyon testleri söz konusu olduğunda bu konuya daha sonra döneceğiz.
  • Tüm Pulumi kaynak özellikleri çıktı olduğundan ve birçoğu eşzamansız olarak değerlendirildiğinden, değerlere erişmek için uygulama yöntemini kullanmamız gerekir. Bu vaatlere ve işleve çok benzer then .
  • Hata mesajında ​​kaynak URN'yi göstermek için çeşitli özellikler kullandığımızdan, işlevi kullanmamız gerekir. pulumi.allonları birleştirmek için.
  • Son olarak bu değerler asenkron olarak hesaplandığı için Mocha'nın yerleşik async geri çağırma özelliğini kullanmamız gerekiyor. done ya da bir sözün geri verilmesi.

Her şeyi ayarladıktan sonra girdilere basit JavaScript değerleri olarak erişebileceğiz. Mülk tags bir haritadır (ilişkisel dizi), dolayısıyla bunun (1) yanlış olmadığından ve (2) bunun için bir anahtar olduğundan emin olacağız. Name. Çok basit ve artık her şeyi test edebiliriz!

Şimdi ikinci çekimizi yazalım. Daha da basit:

 // 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();
                }
            });
        });

Ve son olarak üçüncü testi yazalım. Bu biraz daha karmaşık olacaktır çünkü güvenlik grubuyla ilişkili oturum açma kurallarını (çok sayıda olabilir) ve bu kurallardaki CIDR aralıklarını (ki bunlardan çok sayıda olabilir) arıyoruz. Ama şunları başardık:

    // 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();
                }
            });
        });

Bu kadar. Şimdi testleri çalıştıralım!

Testleri çalıştırma

Çoğu durumda, seçtiğiniz test çerçevesini kullanarak testleri her zamanki gibi çalıştırabilirsiniz. Ancak Pulumi'nin dikkat etmeye değer bir özelliği var.
Tipik olarak, Pulumi programlarını çalıştırmak için, dil çalışma zamanını yapılandıran pulimi CLI (Komut Satırı arayüzü) kullanılır, Pulumi motorunun başlatılmasını kontrol eder, böylece kaynaklarla yapılan işlemler kaydedilebilir ve plana dahil edilebilir vb. Ancak bir sorun var. Test çerçevenizin kontrolü altında çalışırken CLI ile Pulumi motoru arasında iletişim olmayacaktır.

Bu sorunu aşmak için aşağıdakileri belirtmemiz yeterlidir:

  • Ortam değişkeninde yer alan proje adı PULUMI_NODEJS_PROJECT (veya daha genel olarak, PULUMI__PROJECT для других языков).
    Ortam değişkeninde belirtilen yığının adı PULUMI_NODEJS_STACK (veya daha genel olarak, PULUMI__ STACK).
    Yığın yapılandırma değişkenleriniz. Bir ortam değişkeni kullanılarak elde edilebilirler PULUMI_CONFIG ve formatları anahtar/değer çiftlerine sahip JSON haritasıdır.

    Program, yürütme sırasında CLI/motor bağlantısının mevcut olmadığını belirten uyarılar verecektir. Bu önemlidir çünkü programınız aslında hiçbir şeyi konuşlandırmayacak ve yapmak istediğiniz şeyin bu olmaması sürpriz olabilir! Pulumi'ye tam olarak ihtiyacınız olan şeyin bu olduğunu söylemek için PULUMI_TEST_MODE в true.

    Proje adını belirtmemiz gerektiğini düşünün. my-ws, yığın adı devve AWS Bölgesi us-west-2. Mocha testlerini çalıştırmak için kullanılan komut satırı şöyle görünecektir:

    $ PULUMI_TEST_MODE=true 
        PULUMI_NODEJS_STACK="my-ws" 
        PULUMI_NODEJS_PROJECT="dev" 
        PULUMI_CONFIG='{ "aws:region": "us-west-2" }' 
        mocha tests.js

    Bunu beklendiği gibi yapmak bize üç başarısız testimizin olduğunu gösterecek!

    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

    Programımızı düzeltelim:

    "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;
    

    Daha sonra testleri tekrar çalıştırın:

    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)

    Her şey yolunda gitti... Yaşasın! ✓✓✓

    Bugünlük bu kadar ama çevirinin ikinci bölümünde dağıtım testlerinden bahsedeceğiz 😉

Kaynak: habr.com

Yorum ekle