💨

TFLintに入門してみた

に公開

今回はTFLintに入門してみました。今まではTerraformを利用する際にLinterを導入していなかったので、TFLintを用いてLinter入門してみました。

TFLintとは?

TFLintはTerraformのプラグインであり、以下のような特徴を持つようです。

  • 主要なクラウドプロバイダー(AWS/Azure/Google Cloud)の可能性のあるエラー(無効なインスタンスタイプなど)を検索
  • 非推奨の構文や未使用の宣言について警告
  • ベストプラクティス、命名規則を実施

私は主にGoogle Cloudに対して利用していましたが、主要なクラウドプロバイダーを対象としたチェックをしてくれると言うことで、とても有用そうです。

https://github.com/terraform-linters/tflint

使ってみる!

インストール方法

インストール方法は以下に書かれています。私の環境はmacbookなので、以下のコマンドでインストールしました。

brew install tflint

https://github.com/terraform-linters/tflint#installation

tflintを適用してみる!

今回は過去の記事の以下に対して、作成していたコードに問題があるかをチェックさせてみました。

https://zenn.dev/akasan/articles/9c48ed7e2457a6

まずはここで作成したディレクトリ構成とコードを再掲しておきます。

main.tf
variables.tf
modules/
  colab-template/
     main.tf
     variables.tf
   vpc
     main.tf 
     variables.tf
     outputs.tf
main.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

module "vpc" {
  source = "./modules/vpc"

  project_id = var.project_id
  region = var.region
}

module "colab-template" {
  source = "./modules/colab-template"

  project_id = var.project_id
  region = var.region

  network_id = module.vpc.network_id
  subnetwork_id = module.vpc.subnetwork_id
}
variables.tf
variable "project_id" {
  description = "The Google Cloud project ID"
  type        = string
}

variable "region" {
  description = "The Google Cloud region"
  type        = string
  default     = "asia-northeast1"
}
modules/colab-template/main.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_compute_network" "my_network" {
  name = "colab-test-default"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "my_subnetwork" {
  name   = "colab-test-default"
  network = google_compute_network.my_network.id
  region = var.region
  ip_cidr_range = "10.0.1.0/24"
}

resource "google_colab_runtime_template" "runtime-template" {
  name         = "colab-runtime-template"
  display_name = var.colab_enterprise_display_name
  location     = var.region

  machine_spec {
    machine_type = var.colab_enterprise_machine_type
  }

  data_persistent_disk_spec {
    disk_type    = var.data_persistent_disk_spec.disk_type
    disk_size_gb = var.data_persistent_disk_spec.disk_size_gb
  }
  network_spec {
    enable_internet_access = true
    network = var.network_id
    subnetwork = var.subnetwork_id
  }

  idle_shutdown_config {
    idle_timeout = var.idle_timeout
  }

  euc_config {
    euc_disabled = false
  }
modules/colab-template/variables.tf
variable "project_id" {
  description = "The Google Cloud project ID"
  type        = string
}

variable "region" {
  description = "The Google Cloud region"
  type        = string
}

# Colab Enterprise variables
variable "colab_enterprise_display_name" {
  description = "Colab Enterprise display name"
  type        = string
  default     = "sample-template"
}

variable "colab_enterprise_machine_type" {
  description = "Colab Enterprise machine type"
  type        = string
  default     = "n2-standard-4"
}

variable "data_persistent_disk_spec" {
  description = "Data persistent disk spec"
  type = object({
    disk_type    = string
    disk_size_gb = number
  })
  default = {
    disk_type    = "pd-standard"
    disk_size_gb = 100
  }
}

variable "network_id" {
  description = "Network ID"
  type        = string
}

variable "subnetwork_id" {
  description = "Subnetwork ID"
  type        = string
}

variable "idle_timeout" {
  description = "Idle timeout"
  type        = string
  default     = "600s"
}
modules/vpc/main.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_compute_network" "my_network" {
  name = "colab-test-default"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "my_subnetwork" {
  name   = "colab-test-default"
  network = google_compute_network.my_network.id
  region = var.region
  ip_cidr_range = "10.0.1.0/24"
}
modules/vpc/variables.tf
variable "project_id" {
  description = "The Google Cloud project ID"
  type        = string
}

variable "region" {
  description = "The Google Cloud region"
  type        = string
}

variable "vpc_network" {
  description = "VPC network"
  type = object({
    network = string
    subnetwork = string
  })
  default = {
    network = "default"
    subnetwork = "default-asia-northeast1"
  }
}
modules/vpc/outputs.tf
output "network_id" {
  description = "The ID of the created VPC network."
  value       = google_compute_network.my_network.id
}

output "subnetwork_id" {
  description = "The ID of the created VPC subnetwork."
  value       = google_compute_subnetwork.my_subnetwork.id
}

ルートディレクトリにてtflintを実行するとlintが実行されます。今回の結果は以下のようになっておりました。

tflint

# 結果
2 issue(s) found:

Warning: Missing version constraint for provider "google" in `required_providers` (terraform_required_providers)

  on main.tf line 1:
   1: provider "google" {

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.13.0/docs/rules/terraform_required_providers.md

Warning: terraform "required_version" attribute is required (terraform_required_version)

  on main.tf line 1:

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.13.0/docs/rules/terraform_required_version.md

エラーはでず警告が発生して以下を指摘されました。

  • required_providersにてgoogleプロバイダーのバージョン指定がない
  • terraformのrequired_versionの指定がない

lintが通るように修正

先ほど警告された内容に対応するためにmain.tfを以下のように修正してみました。

main.tf
terraform {
  required_version = ">= 1.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 7.3"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

module "vpc" {
  source = "./modules/vpc"

  project_id = var.project_id
  region     = var.region
}

module "colab-template" {
  source = "./modules/colab-template"

  project_id = var.project_id
  region     = var.region

  network_id    = module.vpc.network_id
  subnetwork_id = module.vpc.subnetwork_id
}

追加したのは以下の部分になります。そこでterraformのバージョン指定をしたのと、google providerのバージョンを指定しました。

terraform {
  required_version = ">= 1.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 7.3"
    }
  }
}

ここで改めてtflintを実行すると何も表示されず、lintの結果問題なしと判定されました。

ちなみに構文エラーとかがあると、、、

例えば先ほどのmain.tfterraform部分を以下のように変更してみます。本来であればsourceとversionに値が入っているはずですが、ここではあえて空欄にしてみました。

terraform {
  required_version = ">= 1.0"
  required_providers {
    google = {
      source  = 
      version = 
    }
  }
}

この状態でtflintを実行すると以下のようにエラーが発生しました。みてわかるように、expressionが必要なのにないのでエラーがちゃんとでました。

tflint

# 結果
Failed to load configurations; main.tf:5,17-6,1: Invalid expression; Expected the start of an expression, but found an invalid expression token.:

Error: Invalid expression

  on main.tf line 5, in terraform:
   5:       source  =
   6:       version =

Expected the start of an expression, but found an invalid expression token.

まとめ

今回はTerraformようのLinterであるTFLintに入門してみました。今まではterraformコマンドを利用してエラーが出てなかったので使えてなかったですが、今後はちゃんとlinterを利用して安心安全なIaCの実現ができるように努めていこうと思います。

Discussion