Pulumi を䜿甚したコヌドずしおのむンフラストラクチャのテスト。 パヌト1

皆さん、こんにちは。 このレヌトで新たな流れが始たるこずを期埅しお 「DevOps の実践ずツヌル」 新しい翻蚳を皆さんにシェアしたす。 行く。

Pulumi を䜿甚したコヌドずしおのむンフラストラクチャのテスト。 パヌト1

むンフラストラクチャ コヌドに Pulumi ず汎甚プログラミング蚀語 (Infra Structure as Code) を䜿甚するず、スキルず知識の利甚可胜性、抜象化によるコヌド内のボむラヌプレヌトの排陀、IDE やリンタヌなどのチヌムに銎染みのあるツヌルなど、倚くの利点が埗られたす。 これらすべおの゜フトりェア ゚ンゞニアリング ツヌルは、生産性を向䞊させるだけでなく、コヌドの品質も向䞊させたす。 したがっお、汎甚プログラミング蚀語の䜿甚により、別の重芁な゜フトりェア開発手法を導入できるようになるのは圓然のこずです。 テスト.

この蚘事では、Pulumi がコヌドずしおのむンフラストラクチャのテストにどのように圹立぀かを芋おいきたす。

Pulumi を䜿甚したコヌドずしおのむンフラストラクチャのテスト。 パヌト1

むンフラストラクチャをテストする理由

詳现に入る前に、「そもそもむンフラストラクチャをテストする必芁があるのはなぜですか?」ずいう質問をする䟡倀がありたす。 これには倚くの理由がありたすが、その䞀郚を以䞋に瀺したす。

  • プログラム ロゞックの個々の関数たたは断片の単䜓テスト
  • 特定の制玄に察しおむンフラストラクチャの望たしい状態を怜蚌したす。
  • ストレヌゞ バケットの暗号化の欠劂や、むンタヌネットから仮想マシンぞの保護されおいないオヌプン アクセスなど、䞀般的な゚ラヌの怜出。
  • むンフラストラクチャ プロビゞョニングの実装を確認したす。
  • 「プログラムされた」むンフラストラクチャ内で実行されるアプリケヌション ロゞックのランタむム テストを実行し、プロビゞョニング埌の機胜を確認したす。
  • ご芧のずおり、むンフラストラクチャ テストには幅広いオプションがありたす。 Polumi には、この範囲のあらゆる点でテストするためのメカニズムがありたす。 始めお、それがどのように機胜するかを芋おみたしょう。

単䜓テスト

Pulumi プログラムは、JavaScript、Python、TypeScript、Go などの汎甚プログラミング蚀語で䜜成されたす。 したがっお、テスト フレヌムワヌクを含むツヌルやラむブラリを含め、これらの蚀語の胜力を最倧限に掻甚できたす。 Pulumi はマルチクラりドであるため、どのクラりド プロバむダヌからのテストにも䜿甚できたす。

(この蚘事では、倚蚀語、マルチクラりドにもかかわらず、JavaScript ず Mocha を䜿甚し、AWS を䞭心に説明したす。Python を䜿甚するこずもできたす) unittest、Go テスト フレヌムワヌク、たたはその他の任意のテスト フレヌムワヌクを䜿甚したす。 そしおもちろん、Pulumi は Azure、Google Cloud、Kubernetes ずうたく連携したす。)

これたで芋おきたように、むンフラストラクチャ コヌドをテストする理由はいく぀かありたす。 その XNUMX ぀は埓来の単䜓テストです。 コヌドには、たずえば、CIDR を蚈算したり、名前やタグを動的に蚈算したりする関数が含たれおいる可胜性があるためです。 - おそらくテストしたくなるでしょう。 これは、お気に入りのプログラミング蚀語でアプリケヌションの通垞の単䜓テストを䜜成するのず同じです。
もう少し耇雑にするには、プログラムがリ゜ヌスをどのように割り圓おるかを確認できたす。 説明のために、単玔な EC2 サヌバヌを䜜成する必芁があり、次のこずを確認したいず想像しおみたしょう。

  • むンスタンスにはタグがありたす Name.
  • むンスタンスではむンラむン スクリプトを䜿甚しないでください userData - AMI (むメヌゞ) を䜿甚する必芁がありたす。
  • SSH をむンタヌネットに公開しないでください。

この䟋は以䞋に基づいおいたす 私の䟋 aws-js-webserver:

むンデックス.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;

これは基本的な Pulumi プログラムです。これは単に EC2 セキュリティ グルヌプずむンスタンスを割り圓おるだけです。 ただし、ここでは䞊蚘の XNUMX ぀のルヌルすべおに違反しおいるこずに泚意しおください。 テストを曞いおみたしょう

テストの䜜成

テストの䞀般的な構造は、通垞の Mocha テストず同じようになりたす。

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

それでは、最初のテストを曞いおみたしょう。むンスタンスにタグがあるこずを確認しおください。 Name。 これを確認するには、EC2 むンスタンス オブゞェクトを取埗し、察応するプロパティを確認するだけです。 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();
                }
            });
        });

これは通垞のテストのように芋えたすが、泚目に倀する機胜がいく぀かありたす。

  • デプロむ前にリ゜ヌスの状態をク゚リするため、テストは垞に「蚈画」(たたは「プレビュヌ」) モヌドで実行されたす。 したがっお、倀が単に取埗されない、たたは定矩されないプロパティが倚数ありたす。 これには、クラりド プロバむダヌによっお蚈算されたすべおの出力プロパティが含たれたす。 これはテストでは正垞です。入力デヌタのみをチェックしたす。 この問題に぀いおは、埌で統合テストのずきに再び取り䞊げたす。
  • すべおの Pulumi リ゜ヌス プロパティは出力であり、その倚くは非同期で評䟡されるため、倀にアクセスするには apply メ゜ッドを䜿甚する必芁がありたす。 これはpromiseずafunctionに非垞によく䌌おいたす then .
  • ゚ラヌ メッセヌゞにリ゜ヌス URN を衚瀺するためにいく぀かのプロパティを䜿甚しおいるため、関数を䜿甚する必芁がありたす。 pulumi.allそれらを組み合わせたす。
  • 最埌に、これらの倀は非同期で蚈算されるため、Mocha の組み蟌みの非同期コヌルバック機胜を䜿甚する必芁がありたす。 done たたは玄束を返す。

すべおを蚭定したら、単玔な JavaScript 倀ずしお入力にアクセスできるようになりたす。 財産 tags はマップ (連想配列) なので、(1) false ではないこず、および (2) のキヌがあるこずを確認したす。 Name。 ずおもシンプルなので、䜕でもテストできるようになりたした。

では、XNUMX 番目の小切手を曞いおみたしょう。 さらに簡単です:

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

最埌に、XNUMX 番目のテストを䜜成したしょう。 セキュリティ グルヌプに関連付けられたログむン ルヌル (倚数存圚する可胜性がある) ず、それらのルヌル内の CIDR 範囲 (同様に倚数存圚する可胜性がありたす) を探しおいるため、これは少し耇雑になりたす。 しかし、私たちは次のこずを実行できたした。

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

それだけです。 では、テストを実行しおみたしょう。

テストの実行

ほずんどの堎合、遞択したテスト フレヌムワヌクを䜿甚しお、通垞の方法でテストを実行できたす。 ただし、Pulumi には泚目に倀する機胜が XNUMX ぀ありたす。
通垞、Pulumi プログラムを実行するには、蚀語ランタむムを構成し、リ゜ヌスを䜿甚した操䜜を蚘録しお蚈画に含めるこずができるように Pulumi ゚ンゞンの起動を制埡する pulimi CLI (コマンド ラむン むンタヌフェむス) が䜿甚されたす。 ただし、問題が XNUMX ぀ありたす。 テスト フレヌムワヌクの制埡䞋で実行する堎合、CLI ず Pulumi ゚ンゞンの間に通信はありたせん。

この問題を回避するには、以䞋を指定するだけです。

  • 環境倉数に含たれるプロゞェクト名 PULUMI_NODEJS_PROJECT (たたは、より䞀般的には、 PULUMI__PROJECT Ўля ЎругОх языкПв).
    環境倉数で指定されたスタックの名前 PULUMI_NODEJS_STACK (たたは、より䞀般的には、 PULUMI__ STACK).
    スタック構成倉数。 環境倉数を䜿甚しお取埗できたす。 PULUMI_CONFIG その圢匏はキヌず倀のペアを含む JSON マップです。

    プログラムは、実行䞭に CLI/゚ンゞンぞの接続が利甚できないこずを瀺す譊告を発行したす。 プログラムは実際には䜕もデプロむしないため、これは重芁であり、それが意図したものではない堎合は驚くかもしれたせん。 Pulumi にこれがたさに必芁なものであるこずを䌝えるには、次のようにむンストヌルしたす。 PULUMI_TEST_MODE в true.

    プロゞェクト名を指定する必芁があるず想像しおください。 my-ws、スタック名 dev、および AWS リヌゞョン us-west-2。 Mocha テストを実行するためのコマンド ラむンは次のようになりたす。

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

    これを実行するず、予想どおり、倱敗したテストが XNUMX ぀あるこずがわかりたす。

    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

    プログラムを修正しおみたしょう。

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

    そしお、テストを再床実行したす。

    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)

    すべおうたくいきたした...䞇歳 ✓✓✓

    今日はここたでですが、導入テストに぀いおは翻蚳の埌半でお話したす 😉

出所 habr.com

コメントを远加したす