【Terraform de Azure】 Azure Data Factory のベースを作成してみました

### 概要

「Infrastructure as Code」ということで、Terraform を用いて Azure Data Factory のデータセットまでの基盤を構築し、[この記事](https://qiita.com/turupon/items/41d301780c570e467fcc) で作成した Azure Database for mysql を source に、Azure Blob を sink 等に指定できる準備をします。

### ローカル環境

- macOS Monterey 12.3
- python 3.8.12
- Azure CLI 2.34.1
- terraform v1.0.11

### 前提条件

1. Azure環境がすでに用意されていること（テナント/サブスクリプション）
2. ローカル環境に「azure cli」がインストールされていること
3. ローカル環境に「terraform」環境が構成されていること
4. TerraformでAzure上に環境構築するための[サービスプリンシパルが作成](https://qiita.com/turupon/items/5d024d43a60cd101be94)されており、Terraform のためのローカル環境変数が定義されていること

### 事前準備

[この記事](https://qiita.com/turupon/items/41d301780c570e467fcc) を実行し、Azure Database for mysql のデータベース「iotdummydb」が存在していること

---

## Azure Data Factory の基盤を作成してみます

### terraform 定義ファイルの作成

プロバイダの定義

```main.tf
# プロバイダーの定義
terraform {
  required_providers {
    azurerm =  "~> 2.33"
  }
}

provider "azurerm" {
  features {}
  tenant_id     = var.ARM_TENANT_ID
  client_id     = var.ARM_CLIENT_ID
  client_secret = var.ARM_CLIENT_SECRET
}


# リソースグループ
resource "azurerm_resource_group" "this" {
  name     = var.resource_group_name
  location = var.region
  tags     = var.tags_def
}
```

パラメータ定義ファイル

```variables.tf
# 環境変数（Azureサービスプリンシパル）
variable ARM_TENANT_ID {}
variable ARM_CLIENT_ID {}
variable ARM_CLIENT_SECRET {}

# タグ情報
variable tags_def {
  default = {
    owner      = "ituru"
    period     = "2022-04-28"
    CostCenter = "PSG2"
    Environment = "Demo"
  }
}

# 各種パラメータ
variable resource_group_name {}
variable region {}
variable datafactory_name {}
variable adf_linked_name {}
variable adf_linked_blob_name {}
variable adf_dataset_name {}
variable adf_dataset_blob_name {}
variable adf_table_name {}
variable storage_account_name {}
variable storage_container_name {}

# コネクション定義
variable connect_str01 {}
```

パラメータ値定義ファイル

```terraform.tfvars
# 環境変数の定義（Azureサービスプリンシパル）
ARM_TENANT_ID       = "zzzzzzzz-cccc-4645-5757-zzzzzzzzzzzz"
ARM_CLIENT_ID       = "xxxxxxxx-xxxx-4444-9922-xxxxxxxxxxxx"
ARM_CLIENT_SECRET   = "hogehogehogehogehogehogehogehogege"

# パラメータ値の定義
resource_group_name     = "rg_ituru_adf01"              // リソースグループ名
region                  = "japaneast"                   // 利用リージョン
datafactory_name        = "ituru-adf01"                 // DataFactory名
adf_linked_name         = "adf_link_mysql01"            // ADF Linkサービス名(Source)
adf_dataset_name        = "adf_dataset_mysql01"         // ADF Dataset名(Source)
adf_linked_blob_name    = "adf_link_blob01"             // ADF Linkサービス名(Sink)
adf_dataset_blob_name   = "adf_dataset_blob01"          // ADF Dataset名(Sink)
adf_table_name          = "inventory"                   // ADF Table名
storage_account_name    = "ituruadfaccount"             // ストレージアカウント名
storage_container_name  = "bronze"                      // ストレージアカウント名

# コネクション定義
connect_str01       = "Server=iturumysql01.mysql.database.azure.com;Port=3306;Database=iotdummydb;User=mysqladmin@iturumysql01;SSLMode=1;UseSystemTrustStore=0;Password=NetworldPsg2!"
```

Azure Data Factory 定義ファイル

```datafactory.tf
# Azure Data Factory 
resource "azurerm_data_factory" "this" {
  name                = var.datafactory_name
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
}

# ADF Linked Service of MySQL
resource "azurerm_data_factory_linked_service_mysql" "this" {
  name                = var.adf_linked_name
  data_factory_id     = azurerm_data_factory.this.id
  resource_group_name = azurerm_data_factory.this.resource_group_name
  connection_string   = var.connect_str01
}

# ADF Dataset of MySQL
resource "azurerm_data_factory_dataset_mysql" "this" {
  name                = var.adf_dataset_name
  data_factory_id     = azurerm_data_factory.this.id
  resource_group_name = azurerm_data_factory.this.resource_group_name
  linked_service_name = azurerm_data_factory_linked_service_mysql.this.name
  table_name          = try(var.adf_table_name, null)
}

# ADF Linked Service of BLOB
resource "azurerm_data_factory_linked_service_azure_blob_storage" "this" {
  name              = var.adf_linked_blob_name
  data_factory_id   = azurerm_data_factory.this.id
  resource_group_name = azurerm_data_factory.this.resource_group_name
  connection_string = azurerm_storage_account.this.primary_connection_string
}

# ADF Dataset of json(BLOB)
resource "azurerm_data_factory_dataset_json" "this" {
  name                = var.adf_dataset_blob_name
  data_factory_id     = azurerm_data_factory.this.id
  resource_group_name = azurerm_data_factory.this.resource_group_name
  linked_service_name = azurerm_data_factory_linked_service_azure_blob_storage.this.name

  azure_blob_storage_location {
    container = azurerm_storage_container.this.name
    path      = "foo/mysql/"
    filename  = "iotdummy01.json"
  }

  encoding = "UTF-8"
}
```

Azure Blob 定義ファイル

```blob.tf
# ストレージアカウント
resource "azurerm_storage_account" "this" {
  name                      = var.storage_account_name
  resource_group_name       = azurerm_resource_group.this.name
  location                  = azurerm_resource_group.this.location
  account_tier              = "Standard"
  account_replication_type  = "LRS"
  tags                      = var.tags_def
}

# ストレージコンテナ_Bronze
resource "azurerm_storage_container" "this" {
  name                  = var.storage_container_name
  storage_account_name  = azurerm_storage_account.this.name
  container_access_type = "private"
}
```

### terraform の実行

```
## init
$ terraform init
    :
Terraform has been successfully initialized!

## plan
$ terraform plan
    :
Plan: 8 to add, 0 to change, 0 to destroy.

## apply
$ terraform apply
    :
Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

```

### ローカルの作業ディレクトの状況

```
$ tree -a
.
├── .terraform
│   └── providers
│       └── registry.terraform.io
│           └── hashicorp
│               └── azurerm
│                   └── 2.99.0
│                       └── darwin_amd64
│                           └── terraform-provider-azurerm_v2.99.0_x5
├── .terraform.lock.hcl
├── blob.tf
├── datafactory.tf
├── main.tf
├── terraform.tfstate
├── terraform.tfstate.backup
├── terraform.tfvars
└── variables.tf
```

---

## terraform 実行後の確認

### Azure CLI からの各種確認

```
## 作成先サブスクリプションへの接続
$ az account set --subscription '<Subscription_Name>'


## 作成した Data Factory の詳細表示
$ az datafactory list --resource-group rg_ituru_adf01
[
  {
    "additionalProperties": null,
    "createTime": "2022-04-03T16:33:11.794778+00:00",
    "eTag": "\"2b002b00-0000-0000-0000-47000470000\"",
    "encryption": null,
    "globalParameters": null,
    "id": "/subscriptions/xxxxxxxx-1717-dada-9779-zzzzzzzzzzzz/resourceGroups/rg_ituru_adf01/providers/Microsoft.DataFactory/factories/ituru-adf01",
    "identity": null,
    "location": "japaneast",
    "name": "ituru-adf01",
    "provisioningState": "Succeeded",
    "publicNetworkAccess": "Enabled",
    "repoConfiguration": null,
    "resourceGroup": "rg_ituru_adf01",
    "tags": {},
    "type": "Microsoft.DataFactory/factories",
    "version": "2018-06-01"
  }
]

## 上記のテーブル表示
$ az datafactory list --resource-group rg_ituru_adf01 -o table
CreateTime                        ETag                                    Location    Name         ProvisioningState    PublicNetworkAccess    ResourceGroup    Version
--------------------------------  --------------------------------------  ----------  -----------  -------------------  ---------------------  ---------------  ----------
2022-04-03T16:33:11.794778+00:00  "2b002b00-0000-0000-0000-47000470000"  japaneast   ituru-adf01  Succeeded            Enabled                rg_ituru_adf01   2018-06-01



## 作成した Data Factory の linked-service のリスト表示
$ az datafactory linked-service list --factory-name ituru-adf01 --resource-group rg_ituru_adf01 -o table
Name              ResourceGroup
----------------  ---------------
adf_link_mysql01  rg_ituru_adf01
adf_link_blob01   rg_ituru_adf01


## 作成した Data Factory の dataset の一覧表示
$ az datafactory dataset list --factory-name ituru-adf01 --resource-group rg_ituru_adf01 -o table
Name                 ResourceGroup
-------------------  ---------------
adf_dataset_mysql01  rg_ituru_adf01
adf_dataset_blob01   rg_ituru_adf01


## ストレージ・コンテナ情報の表示
$ az storage container list --account-name ituruadfaccount --output table
Name    Lease Status    Last Modified
------  --------------  -------------------------
bronze                  2022-04-05T13:15:46+00:00

```

#### テスト接続NGの場合

Azure Data Factory から Azure Database for MySQL のテスト接続がうまくいかなかった場合、リソース：「Azure Database for MySQL」の画面の左側タグから「接続のセキュリティ」を選択し、新たに表示される画面の上部の「Azureサービスへのアクセス許可」を「はい」に設定します。

### 作成したリソースの削除

```
## destroy
$ terraform destroy --auto-approve
```

---

### まとめ

このような感じで、Terraform でサクッと Azure Data Factory から Azure Database for MySQL や　Azure BloB と会話できるベース構成を作成できました。 Azure Portal や Azure CLI で構築するのもいいですが、IaC化もいいですね。 が、pipeline や dataset を定義するのは　GUI の方がベターかと、、、、、

### 確認したいこと

Azure Data Factory のGUIから Azure Database for MySQL の Link Service 作成するとき、そのリソースを選択できるが、Terraform で作成すると、単なる MySqlサーバ となっている。データは問題なく取得できているが気になります、、、、、