LoginSignup
1

More than 5 years have passed since last update.

Terraform Resourceのちょっと細かいテストの話 ForceNew編@Accテスト

Last updated at Posted at 2019-02-14

前回、 ConflictsWith編@Accテストという話を書きました。

で今回は ForceNew編 です。

ForceNewとは?

Terraform では、リソースの属性に、 ForceNew というboolean型の属性を付与することができます。
こんな感じです。

func resourceSomethingV1() *schema.Resource {
    return &schema.Resource{

        ()

        Schema: map[string]*schema.Schema{
            "prop1": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                Computed: true,
                ForceNew: true,
            },

            "prop2": &schema.Schema{
                Type:     schema.TypeString,
                Required: true,
                ForceNew: false,
            },

これを true にしておくと、仮にこの属性がUpdateされた場合に、リソースが一旦削除され、その後作成されるという挙動をします。

例えば上記ですと、

  • prop1 を変更するとインスタンスは削除新設される
  • prop2 は変更しても既存のリソースが維持される

ということなんですが、さて、これって案外恐ろしい仕様だと思うんですよね。

うっかり tfファイルいじっちゃって、気づいたらリソース消えててもTerraform的には何も気づけ無いわけで。

ということで、Accテスト内で、リソースの変更を試験する際に、 ForceNew発動してないよね? というのを併せて試験しておくと安心だな・・・と思い実装をし、 うまくいった! ・・・と思っていました。

・・・が、その後で気づいたのですが、これ、普通に OpenStack のProviderとかに入ってましたね。
なんか自分で閃いた感があったんですが、全然でした(笑

とはいえ、有用なことだと思ったので書いておこうかと思います。

実装例

例えばこんなAccテストです。以下は、逆に これを変更したら正しくForceNewされるよね? というテストにしてますが、 testAccCheckSomethingV1IDsDoNotMatch の判定条件を変えればすぐ逆の挙動にできます。

テスト本体部

Something をこのAccテストでCRUDされるリソースのtypeだとします。

func TestAccSomething(t *testing.T) {
    var something_1 Something
    var something_2 Something

    resource.Test(t, resource.TestCase{
        PreCheck:     func() { testAccPreCheck(t) },
        Providers:    testAccProviders,
        ()
        Steps: []resource.TestStep{
            resource.TestStep{
                Config: testAccSomethingV1ForceNew1,
                Check: resource.ComposeTestCheckFunc(
                    testAccCheckSomethingV1Exists(
                        "myprovider_something.something_1", &something_1),
                ),
            },
            resource.TestStep{
                Config: testAccSomethingV1ForceNew1,
                Check: resource.ComposeTestCheckFunc(
                    testAccCheckComputeV2InstanceExists(
                        "myprovider_something.something_1", &something_2),
                    testAccCheckSomethingV1IDsDoNotMatch(&something_1, &something_2),
                ),
            },
        },
    })
}

func testAccCheckSomethingV1IDsDoNotMatch(
    something1, something2 *Something) resource.TestCheckFunc {
    return func(s *terraform.State) error {
        if something1.ID == something2.ID {
            return fmt.Errorf("Something was not recreated")
        }
        return nil
    }
}

テスト用コンフィグ部

const testAccSomethingV1ForceNew1 = `
resource "myprovider_something" "something_1" {
  region = "myregion1"
  name = "name1"
}`

const testAccSomethingV1ForceNew2 = `
resource "myprovider_something" "something_1" {
  region = "myregion2" <-- ここを変えたからForceNewされるという期待
  name = "name1"
}`

要は、

  • リソースが再作成されるとIDが変わるはず
  • コンフィグ変更後の terraform apply で特定のリソースのIDが一致しない=ForceNewされた

ということです。

実際には通常変更可能な属性の変更テストにおいて、ForceNew されてない ことを確認するのに使ったほうがいい気がします。(リグレッション的な観点で)

ということで、 ForceNew編でした。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1