前回、 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編でした。