Terraform v0.10 + Azure Rm Provider の Tips その１

今日はほぼ一日久々に Terraform と格闘していた。昔は、VM をプロビジョンするだけの使い方だったが、ARM は確実なんだけど、やっぱり、Terraform で書くとホンマ楽だ。HCL 最高。ミッシェルが、昔は JSON でコンフィグつくっていたけど、間違いと気づいて HCL を作ったという。あんた天才や。

# Tips.1 新しい Terraform はプロバイダが分かれている。

久々に触るとちょっとびっくりしたが、コードを書いて

```hcl
terraform plan
```

をたたくと次のように怒られる。

```
Plugin reinitialization required. Please run "terraform init".
Reason: Could not satisfy plugin requirements.

Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.

1 error(s) occurred:

* provider.azurerm: no suitable version installed
  version requirements: "(any version)"
  versions installed: none

Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints from each module, run "terraform providers".

error satisfying plugin requirements

```

指示どおりにしてみると、プロバイダがダウンロードされる。

```
$ terraform init

Initializing provider plugins...
- Downloading plugin for provider "azurerm"...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.azurerm: version = "~> 0.1"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

```

やっぱ HashiCorp のプロダクトは使いやすい。指示のままだ。ちなみに、Azure の Provider は以前は、terraform のリポジトリに含まれていたが今はここ。たくさん貢献しよう。

* [Terraform azurerm provider](https://github.com/terraform-providers/terraform-provider-azurerm)

# Tips 2. 最近は VM よりもずっと沢山のリソースがサポートされている

ふと久々にマニュアルを見ると、結構な数のリソースがカバーされている。

* [Microsoft Azure Provider](https://www.terraform.io/docs/providers/azurerm/index.html)

Storage Account とかも、ARM だと、中のコンテナまでつくれないが、terraform なら一撃。

```hcl
resource "azurerm_storage_account" "test" {
    name                    =   "${var.storage_account_name}"
    resource_group_name     =   "${azurerm_resource_group.test.name}"
    location                =   "${azurerm_resource_group.test.location}"
    account_type            =   "Standard_LRS"
    tags {
        environment = "${var.environment}"
    }
}

resource "azurerm_storage_container" "test" {
    name                    =   "${var.storage_account_container_name}"
    resource_group_name     =   "${azurerm_resource_group.test.name}"
    storage_account_name    =   "${azurerm_storage_account.test.name}"
    container_access_type   =   "private"
}

output "Storage Account Blob Connection String" {
    value = "${azurerm_storage_account.test.primary_blob_connection_string}"
}
```

ちゃんと `Connection String` までとってこれる。

ちなみに今回私が作ったのは

* Key Vault
* Event Hubs
* Storage Account/Container
* SQL Server/Database
* Redis Cache

他に、Tips 3で

* OMS
* Azure Functions
* Azure Data Factory
* Azure Stream Analytics 

あたりをプロビジョン予定。

# Tips 3. 使えないやつは、ARM と連携させる

まだ未サポートのリソースは、ARM を呼ぶこともできる。以下は、OMS の ARM テンプレートと連携させた例だ。

```hcl

# OMS (Call ARM Template)

resource "azurerm_template_deployment" "test" {
    name                            =   "oms-deployment-01"
    resource_group_name             =   "${azurerm_resource_group.test.name}" 
    template_body                   =   "${file("${path.cwd}/oms/template.json")}"   
    parameters                      {
        workspaceName               =   "telemetrySpike5"
        serviceTier                 =   "Free"
        location                    =   "West Central US"
    } 
    deployment_mode                 =   "Incremental"
}

```

こんなコードを書くと、ARM のテンプレートを読み込んで実行できるので、結局なんでもできる。ARMの実行結果も、output で取れる。ちなみに、`parameter.json` はどうなるかというと、parameters に書き換える必要があるけど、それだけ。

# Tips 4. ２回同じ名前でやったらあかんリソースがたまにある

Storage Account の名前は、一旦消しても、数時間は同じ名前が使えない。同じく、OMS の Workspace 名とか、Redis の名前も同じで、消した後に同じ名前で作成しようとしたら怒られた。何らかの工夫が必要である。ARM の時は、Storage Account は、uniqueString という関数でユニークな名前にするのが定石だった。

# Tips 5. タイムアウト、何故かリソースができないのは、コンフィグが間違ってるからかも

```
azurerm_redis_cache.test: Still creating... (9m20s elapsed)
azurerm_redis_cache.test: Still creating... (9m30s elapsed)
azurerm_redis_cache.test: Still creating... (9m40s elapsed)
azurerm_redis_cache.test: Still creating... (9m50s elapsed)
azurerm_redis_cache.test: Still creating... (10m0s elapsed)
azurerm_redis_cache.test: Still creating... (10m10s elapsed)
azurerm_redis_cache.test: Still creating... (10m20s elapsed)
azurerm_redis_cache.test: Still creating... (10m30s elapsed)
azurerm_redis_cache.test: Still creating... (10m40s elapsed)
azurerm_redis_cache.test: Still creating... (10m50s elapsed)
azurerm_redis_cache.test: Still creating... (11m0s elapsed)
azurerm_redis_cache.test: Still creating... (11m10s elapsed)
azurerm_redis_cache.test: Still creating... (1h51m51s elapsed)
```
こんな感じで延々とおわならないケースがあると、うーん、これは、Redis のせいだろうな。と思うことだろう。ところが、そうとも限らない。経験則でいくと、このようなケースは、10中8, 9 コンフィグに設定している値が間違えている。サービスの範囲を超えているとか、そういうのである。このあと、これは、下記のようなエラーをはいた。（むっちゃ後に）

```
3 error(s) occurred:

* azurerm_eventhub.test: 1 error(s) occurred:

* azurerm_eventhub.test: eventhub.EventHubsClient#CreateOrUpdate: Fa      ilure responding to request: StatusCode=400 -- Original Error: autor      est/azure: Service returned an error. Status=400 Code="BadRequest" M      essage="SubCode=40000. The value '2' for MessageRetentionInDays is n      ot valid for the Basic tier. the value cannot exceed '1' day(s).\r\n      Parameter name: MessageRetentionInDays. TrackingId:666aef31-96ce-49c      6-bf34-ea9deb66d766_M5_M5_G25, SystemTracker:spike2hub.servicebus.wi      ndows.net:telemetry, Timestamp:8/11/2017 11:18:19 PM"
* azurerm_sql_server.test: 1 error(s) occurred:

* azurerm_sql_server.test: Error creating SQL Server: PUT https://ma      nagement.azure.com/subscriptions//resourceGroups/spiketestrg3/providers/Microsoft.Sql/servers/spike2      db?api-version=2014-04-01 giving up after 5 attempts
* azurerm_redis_cache.test: 1 error(s) occurred:

* azurerm_redis_cache.test: azure.BearerAuthorizer#WithAuthorization      : Failed to refresh the Token for request to https://management.azur      e.com/subscriptions//resourceGro      ups/spiketestrg3/providers/Microsoft.Cache/redis/spike5redis?api-ver      sion=2016-04-01: StatusCode=0 -- Original Error: adal: Failed to exe      cute the refresh request. Error = 'Post https://login.microsoftonlin      e.com/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/token?api-version=      1.0: dial tcp: lookup login.microsoftonline.com: no such host'

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

```

ちなみに、今回はどんなのがあったかというと、EventHub を設定して、sku がBasic Plan だったら、`message_retention` が 1 までなのに、2 になっていたとか(これ、マニュアルのサンプルがそうなんすけど、、、pull request だな)、Redis の sku が BASIC のときは、max clients = 256 なのに、1000になってたりとか。 resource group がみつからないとか。ちなみに、resource group の件は調査中だが、tag に関係しているかも。今は、resrouce group を先につくっておいて、先に進めている。

ちなみに、こういうときに、何分も待つのはバカバカしいだろう。だから、そういうときは、そういった、相関のあるコンフィグを疑うのと、Azure のポータルでエラーを見たほうがいい。こっちに先にでている可能性が高い。(terraform はタイムアウトまでやってるっぽい)

![terraform01.png](https://qiita-image-store.s3.amazonaws.com/0/3470/7a5f7f1b-780b-e4f7-fc49-3deb36f78109.png)

だから、一気にデプロイせず、１つのリソースだけ切り出して、個別にデプロイの実験をするほうがおそらく確実だろう。待ち時間が圧倒的に違う。

# Tips 6. Cosmos DB は使えなかった。

謎のエラーで使えなかった。リソースが無い感じ。REST API が変ったのかな。Issue を投げておいた。

[CosmosDB throws Unknown service error](https://github.com/terraform-providers/terraform-provider-azurerm/issues/241)

# まとめ

Terraform はシンプルでガチ最高だけど、まだまだ、コミュニティの力が必要だ、さあ、貢献してヒーローになるチャンスや！わしもやるぞ！

issue の報告に加えて、ドキュメントの pull request 送っときました。

* [Edit the sample parameter for EventHub](https://github.com/terraform-providers/terraform-provider-azurerm/pull/242)