ネットワークエンジニアのITブログ

長らくネットワークで生活してきましたが、ここ数年クラウドとサーバー系に触れる機会が増えて、日々成長しています。最近のお気に入りはNSXALBとGoogle Cloud。

TerraformでNSXALBのVSを作成してみる

今まで、VMware、Azure、AWSと触ってきましたが、一切自動化というのをしてきていませんでした。
先日、Google Cloudを初めて触った際に同僚からTerraform使うと構築楽だよと言われ触ったところ、構築した環境をコマンド一つで削除できることに感動しました。
業務では、構築がうまくいかない場合、作業を切り戻すこともあり、その手順も調べながら作成していましたが、Terraformは、あらかじめて設定した内容を「apply」で実行し、作業前の状態に戻すのを「destroy」というコマンドだけで実現できます。
これをVMwareの製品でも実現したいと思い、NSXALBのVS作成手順を調べたので紹介します。

ネットワーク構成

ネットワーク構成は、vSphere7で構築したホームラボ環境を利用します。
今回、赤字で記載しているVIPへアクセスすると、2台のLinuxサーバに負荷分散される環境を作っていきます。

Terraformのインストール

ダウンロードと配置

今回、Terraformを実行する端末は、WIndows10になるため、Windows版のTerraformをインストールします。
Terraformの公式サイトから、環境に合わせてダウンロードします。
developer.hashicorp.com
ダウンロードしたファイルを解凍し、実行ファイルを任意の場所に配置します。
今回は、「c:\work\Terraform\alb」配下に「terraform.exe」を配置しました。

c:\work\Terraform\alb>
c:\work\Terraform\alb>dir
2024/01/14  22:45    <DIR>          .
2024/01/14  22:45    <DIR>          ..
2023/12/13  18:11        82,848,432 terraform.exe
               1 個のファイル          82,848,432 バイト
               2 個のディレクトリ  663,619,153,920 バイトの空き領域
c:\work\Terraform\alb>
Pathを通す

Pathを通すために環境変数の設定を行います。
[コントロールパネル]-[システムとセキュリティ]-[システム]-[システムの詳細設定]から「環境変数」をクリックします。

変数の「Path」を選択し、編集をクリックします。

新規から画面のように「Terraform.exe」を配置したフォルダを設定します。

設定後は、全て「OK」をクリックして設定を閉じます。
コマンドプロンプトを起動し、Pathが通っていることを確認します。
正しく設定されていれば、Terraformのバージョンが表示されます。

C:\Users\hippi>terraform -v
Terraform v1.6.6
on windows_amd64
C:\Users\hippi>

tfファイルの作成

設定を投入するための設定ファイル(tfファイル)を作成します。

providerファイルの作成

最初にNSXALBに接続するための情報を「Provider.tf」として作成します。
拡張子を.tfとしたテキストファイルを作成し、以下の情報を貼り付けます。

#NSXALB接続定義
terraform {
  required_providers {
    avi = {
      source  = "vmware/avi"
      version = "22.1.3"
    }
  }
}

#認証情報設定
provider "avi" {
  avi_controller = "avi51.home.local"
  avi_tenant     = "admin"
#ユーザー名を設定
  avi_username   = "xxxxxx"
#パスワードを設定
  avi_password   = "xxxxxx"
  avi_version    = "22.1.3"
}
mainファイルの作成

Pool、VIP、VSの情報を「main.tf」として作成します。
拡張子を.tfとしたテキストファイルを作成し、以下の情報を貼り付けます。

#Tenant情報取得
data "avi_tenant" "admin" {
  name = "admin"
}

#Clouds情報取得
data "avi_cloud" "default_cloud" {
  name       = "Defaul-Cloud"
  tenant_ref = data.avi_tenant.admin.id
}

#vrf情報取得
data "avi_vrfcontext" "vrf01" {
  name       = "vrf01"
  tenant_ref = data.avi_tenant.admin.id
}

#HealthMonitor作成
resource "avi_healthmonitor" "monitor" {
  name              = "custom-HTTP"
  type              = "HEALTH_MONITOR_HTTP"
  send_interval     = "5"
  receive_timeout   = "4"
  successful_checks = "2"
  failed_checks     = "2"
}

#Pool作成
resource "avi_pool" "pool01" {
  name                = "pool_http"
  tenant_ref          = data.avi_tenant.admin.id
  cloud_ref           = data.avi_cloud.default_cloud.id
  vrf_ref             = data.avi_vrfcontext.vrf01.id
  lb_algorithm        = "LB_ALGORITHM_ROUND_ROBIN"
  health_monitor_refs = [avi_healthmonitor.monitor.id]
  servers {
    ip {
      type = "V4"
      addr = "192.168.10.71"
    }
    port = 80
  }
  servers {
    ip {
      type = "V4"
      addr = "192.168.10.72"
    }
    port = 80
  }
}

#VIP作成
resource "avi_vsvip" "vip01" {
  name = "VIP_192.168.3.11"
  vip {
    vip_id = "0"
    ip_address {
      type = "V4"
      addr = "192.168.3.11"
    }
    auto_allocate_ip = false
  }
  tenant_ref      = data.avi_tenant.admin.id
  cloud_ref       = data.avi_cloud.default_cloud.id
  vrf_context_ref = data.avi_vrfcontext.vrf01.id
}

#VS作成
resource "avi_virtualservice" "vs01" {
  name            = "vs_http"
  tenant_ref      = data.avi_tenant.admin.id
  pool_ref        = avi_pool.pool01.id
  vsvip_ref       = avi_vsvip.vip01.id
  cloud_ref       = data.avi_cloud.default_cloud.id
  vrf_context_ref = data.avi_vrfcontext.vrf01.id
  cloud_type      = "CLOUD_NONE"
  services {
    port       = 80
    enable_ssl = false
  }
}

リソースの作成

事前の設定が完了したので、実際にコマンドを実行してリソースを作成していきます。

初期化&プラグインのインストール(teraform init)

まず最初に、作成したtfファイルのあるディレクトリに移動し、「terraform init」を実行します。
これは、Terraform 構成ファイルを含む作業ディレクトリを初期化し、必要なプラグインやモジュールのインストールをしてくれます。

PS C:\work\Terraform\alb>
PS C:\work\Terraform\alb> terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of vmware/avi from the dependency lock file
- Using previously-installed vmware/avi v22.1.3

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.
PS C:\work\Terraform\alb>
PS C:\work\Terraform\alb>
実行計画(terraform plan)

続いて、「terraform plan」を実行します。
これは、リソースを作成する実行計画にあたるもので、どのようなリソースに対してどのような設定を行うかあらかじめ表示してくれます。
もし、コードに問題があれば、どこでエラーが発生しているか教えてくれます。

PS C:\work\Terraform\alb>
PS C:\work\Terraform\alb> terraform plan
data.avi_tenant.admin: Reading...
data.avi_tenant.admin: Read complete after 0s [id=https://avi51.home.local/api/tenant/admin]
data.avi_vrfcontext.vrf01: Reading...
data.avi_cloud.default_cloud: Reading...
data.avi_vrfcontext.vrf01: Read complete after 0s [id=https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab]
data.avi_cloud.default_cloud: Read complete after 0s

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # avi_healthmonitor.monitor will be created
  + resource "avi_healthmonitor" "monitor" {
      + allow_duplicate_monitors = (known after apply)
      + description              = (known after apply)
      + disable_quickstart       = (known after apply)
      + failed_checks            = "2"
      + id                       = (known after apply)
      + is_federated             = "false"
      + monitor_port             = (known after apply)
      + name                     = "custom-HTTP"
      + receive_timeout          = "4"
      + send_interval            = "5"
      + successful_checks        = "2"
      + tenant_ref               = (known after apply)
      + type                     = "HEALTH_MONITOR_HTTP"
      + uuid                     = (known after apply)
    }

  # avi_pool.pool01 will be created
  + resource "avi_pool" "pool01" {
      + analytics_profile_ref                 = (known after apply)
      + append_port                           = "NON_DEFAULT_80_443"
      + application_persistence_profile_ref   = (known after apply)
      + autoscale_launch_config_ref           = (known after apply)
      + autoscale_policy_ref                  = (known after apply)
      + capacity_estimation                   = "false"
      + capacity_estimation_ttfb_thresh       = "0"
      + cloud_config_cksum                    = (known after apply)
      + cloud_ref                             = (known after apply)
      + connection_ramp_duration              = "10"
      + created_by                            = (known after apply)
      + default_server_port                   = "80"
      + delete_server_on_dns_refresh          = "true"
      + description                           = (known after apply)
      + east_west                             = (known after apply)
      + enable_http2                          = "false"
      + enabled                               = "true"
      + fewest_tasks_feedback_delay           = "10"
      + graceful_disable_timeout              = "1"
      + gslb_sp_enabled                       = (known after apply)
      + health_monitor_refs                   = (known after apply)
      + host_check_enabled                    = "false"
      + id                                    = (known after apply)
      + ignore_server_port                    = "false"
      + ignore_servers                        = false
      + inline_health_monitor                 = "true"
      + ipaddrgroup_ref                       = (known after apply)
      + lb_algo_rr_per_se                     = "false"
      + lb_algorithm                          = "LB_ALGORITHM_ROUND_ROBIN"
      + lb_algorithm_consistent_hash_hdr      = (known after apply)
      + lb_algorithm_core_nonaffinity         = "2"
      + lb_algorithm_hash                     = "LB_ALGORITHM_CONSISTENT_HASH_SOURCE_IP_ADDRESS"
      + lookup_server_by_name                 = "false"
      + max_concurrent_connections_per_server = "0"
      + min_health_monitors_up                = (known after apply)
      + min_servers_up                        = (known after apply)
      + name                                  = "pool_http"
      + pki_profile_ref                       = (known after apply)
      + pool_type                             = "POOL_TYPE_GENERIC_APP"
      + request_queue_depth                   = "128"
      + request_queue_enabled                 = "false"
      + resolve_pool_by_dns                   = (known after apply)
      + rewrite_host_header_to_server_name    = "false"
      + rewrite_host_header_to_sni            = "false"
      + routing_pool                          = "false"
      + server_disable_type                   = "DISALLOW_NEW_CONNECTION"
      + server_name                           = (known after apply)
      + server_timeout                        = "0"
      + service_metadata                      = (known after apply)
      + sni_enabled                           = "true"
      + ssl_key_and_certificate_ref           = (known after apply)
      + ssl_profile_ref                       = (known after apply)
      + tenant_ref                            = "https://avi51.home.local/api/tenant/admin"
      + tier1_lr                              = (known after apply)
      + use_service_port                      = "false"
      + use_service_ssl_mode                  = "false"
      + uuid                                  = (known after apply)
      + vrf_ref                               = "https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab"

      + servers {
          + autoscaling_group_name    = (known after apply)
          + availability_zone         = (known after apply)
          + description               = (known after apply)
          + enabled                   = "true"
          + external_orchestration_id = (known after apply)
          + external_uuid             = (known after apply)
          + hostname                  = (known after apply)
          + mac_address               = (known after apply)
          + nw_ref                    = (known after apply)
          + port                      = "80"
          + preference_order          = (known after apply)
          + prst_hdr_val              = (known after apply)
          + ratio                     = "1"
          + resolve_server_by_dns     = "false"
          + rewrite_host_header       = "false"
          + server_node               = (known after apply)
          + static                    = "false"
          + verify_network            = "false"
          + vm_ref                    = (known after apply)

          + ip {
              + addr = "192.168.10.71"
              + type = "V4"
            }
        }
      + servers {
          + autoscaling_group_name    = (known after apply)
          + availability_zone         = (known after apply)
          + description               = (known after apply)
          + enabled                   = "true"
          + external_orchestration_id = (known after apply)
          + external_uuid             = (known after apply)
          + hostname                  = (known after apply)
          + mac_address               = (known after apply)
          + nw_ref                    = (known after apply)
          + port                      = "80"
          + preference_order          = (known after apply)
          + prst_hdr_val              = (known after apply)
          + ratio                     = "1"
          + resolve_server_by_dns     = "false"
          + rewrite_host_header       = "false"
          + server_node               = (known after apply)
          + static                    = "false"
          + verify_network            = "false"
          + vm_ref                    = (known after apply)

          + ip {
              + addr = "192.168.10.72"
              + type = "V4"
            }
        }
    }

  # avi_virtualservice.vs01 will be created
  + resource "avi_virtualservice" "vs01" {
      + active_standby_se_tag              = "ACTIVE_STANDBY_SE_1"
      + advertise_down_vs                  = "false"
      + allow_invalid_client_cert          = "false"
      + analytics_profile_ref              = (known after apply)
      + application_profile_ref            = (known after apply)
      + azure_availability_set             = (known after apply)
      + bot_policy_ref                     = (known after apply)
      + bulk_sync_kvcache                  = "false"
      + close_client_conn_on_config_update = "false"
      + cloud_config_cksum                 = (known after apply)
      + cloud_ref                          = (known after apply)
      + cloud_type                         = "CLOUD_NONE"
      + created_by                         = (known after apply)
      + delay_fairness                     = "false"
      + description                        = (known after apply)
      + east_west_placement                = "false"
      + enable_autogw                      = "true"
      + enable_rhi                         = (known after apply)
      + enable_rhi_snat                    = (known after apply)
      + enabled                            = "true"
      + error_page_profile_ref             = (known after apply)
      + flow_dist                          = "LOAD_AWARE"
      + flow_label_type                    = "NO_LABEL"
      + fqdn                               = (known after apply)
      + host_name_xlate                    = (known after apply)
      + id                                 = (known after apply)
      + ign_pool_net_reach                 = "false"
      + limit_doser                        = "false"
      + max_cps_per_client                 = "0"
      + microservice_ref                   = (known after apply)
      + min_pools_up                       = (known after apply)
      + name                               = "vs_http"
      + network_profile_ref                = (known after apply)
      + network_security_policy_ref        = (known after apply)
      + pool_group_ref                     = (known after apply)
      + pool_ref                           = (known after apply)
      + remove_listening_port_on_vs_down   = "false"
      + scaleout_ecmp                      = "false"
      + se_group_ref                       = (known after apply)
      + security_policy_ref                = (known after apply)
      + server_network_profile_ref         = (known after apply)
      + service_metadata                   = (known after apply)
      + ssl_profile_ref                    = (known after apply)
      + ssl_sess_cache_avg_size            = "1024"
      + sso_policy_ref                     = (known after apply)
      + tenant_ref                         = "https://avi51.home.local/api/tenant/admin"
      + test_se_datastore_level_1_ref      = (known after apply)
      + traffic_clone_profile_ref          = (known after apply)
      + traffic_enabled                    = "true"
      + type                               = "VS_TYPE_NORMAL"
      + use_bridge_ip_as_vip               = "false"
      + use_vip_as_snat                    = "false"
      + uuid                               = (known after apply)
      + vh_parent_vs_ref                   = (known after apply)
      + vh_type                            = "VS_TYPE_VH_SNI"
      + vrf_context_ref                    = "https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab"
      + vsvip_cloud_config_cksum           = (known after apply)
      + vsvip_ref                          = (known after apply)
      + waf_policy_ref                     = (known after apply)
      + weight                             = "1"

      + services {
          + enable_http2                     = "false"
          + enable_ssl                       = "false"
          + horizon_internal_ports           = "false"
          + is_active_ftp_data_port          = "false"
          + override_application_profile_ref = (known after apply)
          + override_network_profile_ref     = (known after apply)
          + port                             = "80"
          + port_range_end                   = "0"
        }
    }

  # avi_vsvip.vip01 will be created
  + resource "avi_vsvip" "vip01" {
      + cloud_ref                = (known after apply)
      + east_west_placement      = "false"
      + id                       = (known after apply)
      + name                     = "VIP_192.168.3.11"
      + tenant_ref               = "https://avi51.home.local/api/tenant/admin"
      + tier1_lr                 = (known after apply)
      + uuid                     = (known after apply)
      + vrf_context_ref          = "https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab"
      + vsvip_cloud_config_cksum = (known after apply)

      + vip {
          + auto_allocate_floating_ip = "false"
          + auto_allocate_ip          = "false"
          + auto_allocate_ip_type     = "V4_ONLY"
          + availability_zone         = (known after apply)
          + avi_allocated_fip         = "false"
          + avi_allocated_vip         = "false"
          + enabled                   = "true"
          + floating_subnet6_uuid     = (known after apply)
          + floating_subnet_uuid      = (known after apply)
          + network_ref               = (known after apply)
          + port_uuid                 = (known after apply)
          + prefix_length             = "32"
          + subnet6_uuid              = (known after apply)
          + subnet_uuid               = (known after apply)
          + vip_id                    = "0"

          + ip_address {
              + addr = "192.168.3.11"
              + type = "V4"
            }
        }
    }

Plan: 4 to add, 0 to change, 0 to destroy.

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
PS C:\work\Terraform\alb>
PS C:\work\Terraform\alb> 

実行結果から、「Plan: 4 to add, 0 to change, 0 to destroy.」4つのリソースを追加するという表示が出ており、エラーも内情であることを確認できます。

リソースの作成(terraform apply)

実行計画に問題がないことを確認したら、「terraform apply」を実行してリソースを作成します。
途中で、「Enter a value:」という表示が出たら、「yes」を入力してEnterキーを押下するとリソースが作成されます。

PS C:\work\Terraform\alb> terraform apply
data.avi_tenant.admin: Reading...
data.avi_tenant.admin: Read complete after 1s [id=https://avi51.home.local/api/tenant/admin]
data.avi_vrfcontext.vrf01: Reading...
data.avi_cloud.default_cloud: Reading...
data.avi_cloud.default_cloud: Read complete after 0s
data.avi_vrfcontext.vrf01: Read complete after 0s [id=https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab]

~省略~

Plan: 4 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: <strong>yes</strong>

avi_healthmonitor.monitor: Creating...
avi_vsvip.vip01: Creating...
avi_healthmonitor.monitor: Creation complete after 0s [id=https://avi51.home.local/api/healthmonitor/healthmonitor-33542429-cf4d-4d8f-b9f9-22578b353e2d]
avi_pool.pool01: Creating...
avi_vsvip.vip01: Creation complete after 1s [id=https://avi51.home.local/api/vsvip/vsvip-15586354-ed1f-41d4-bb5d-b2d358a858fe]
avi_pool.pool01: Creation complete after 1s [id=https://avi51.home.local/api/pool/pool-55d4b021-fca5-481a-98ef-621e9fd046fc]
avi_virtualservice.vs01: Creating...
avi_virtualservice.vs01: Creation complete after 0s [id=https://avi51.home.local/api/virtualservice/virtualservice-aa1e84d4-ce26-4106-8198-1bb504565419]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
PS C:\work\Terraform\alb> 

最終行に「Apply complete!」と表示されていたら作成成功になります。

実行結果の確認

実際にGUIで確認するとリソースが作成されていることが確認できました。

リソースの削除(terraform destroy)

作成したリソースを削除する場合は、「terraform destroy」を実行します。
このコマンドを実行すると「terraform apply」で作成したリソースをすべて削除できます。

PS C:\work\Terraform\alb>
PS C:\work\Terraform\alb> terraform destroy
data.avi_tenant.admin: Reading...
avi_healthmonitor.monitor: Refreshing state... [id=https://avi51.home.local/api/healthmonitor/healthmonitor-33542429-cf4d-4d8f-b9f9-22578b353e2d]
data.avi_tenant.admin: Read complete after 1s [id=https://avi51.home.local/api/tenant/admin]
data.avi_vrfcontext.vrf01: Reading...
data.avi_cloud.default_cloud: Reading...
data.avi_vrfcontext.vrf01: Read complete after 0s [id=https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab]
data.avi_cloud.default_cloud: Read complete after 0s
avi_vsvip.vip01: Refreshing state... [id=https://avi51.home.local/api/vsvip/vsvip-15586354-ed1f-41d4-bb5d-b2d358a858fe]
avi_pool.pool01: Refreshing state... [id=https://avi51.home.local/api/pool/pool-55d4b021-fca5-481a-98ef-621e9fd046fc]
avi_virtualservice.vs01: Refreshing state... [id=https://avi51.home.local/api/virtualservice/virtualservice-aa1e84d4-ce26-4106-8198-1bb504565419]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

~省略~

Plan: 0 to add, 0 to change, 4 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

avi_virtualservice.vs01: Destroying... [id=https://avi51.home.local/api/virtualservice/virtualservice-aa1e84d4-ce26-4106-8198-1bb504565419]
avi_virtualservice.vs01: Destruction complete after 0s
avi_vsvip.vip01: Destroying... [id=https://avi51.home.local/api/vsvip/vsvip-15586354-ed1f-41d4-bb5d-b2d358a858fe]
avi_pool.pool01: Destroying... [id=https://avi51.home.local/api/pool/pool-55d4b021-fca5-481a-98ef-621e9fd046fc]
avi_vsvip.vip01: Destruction complete after 0s
avi_pool.pool01: Destruction complete after 0s
avi_healthmonitor.monitor: Destroying... [id=https://avi51.home.local/api/healthmonitor/healthmonitor-33542429-cf4d-4d8f-b9f9-22578b353e2d]
avi_healthmonitor.monitor: Destruction complete after 0s

Destroy complete! Resources: 4 destroyed.
PS C:\work\Terraform\alb> 

コマンドが正常に処理され、リソースが削除されたことが確認できました。

便利なツールやコマンド

tfファイルは、テキストエディタで作成することができますが、コードエディタを使用すると、コードの入力補完やコマンドの実行もできてしまう優れものです。

Visual Studio Code

Microsoft社が無償で提供しているコードエディタです。
私もこれを利用してコードをの作成や実行をしています。
特に「表示」から「ターミナル」を選択すると、画面下部にコマンドプロンプトが表示されるので、コードの作成や修正をしながら、すぐにplan、apply、destroy を実行できるのは便利です。

terraform show

「terraform show」コマンドは、適用済みの全リソースの情報を確認することができます。
コードを作成する際に、パラメーターの名称がわからない時など、基本のパラメータのみTerraformで実行し、その後、GUIで設定してこのコマンドを事項すると、どのパラメータに作成されたか確認することができます。

PS C:\work\Terraform\alb> terraform show
# data.avi_cloud.default_cloud:
data "avi_cloud" "default_cloud" {}

# data.avi_tenant.admin:
data "avi_tenant" "admin" {
    config_settings     = []
    configpb_attributes = []
    id                  = "https://avi51.home.local/api/tenant/admin"
    name                = "admin"
    uuid                = "admin"
}

# data.avi_vrfcontext.vrf01:
data "avi_vrfcontext" "vrf01" {
    bfd_profile              = []
    bgp_profile              = []
    cloud_ref                = "https://avi51.home.local/api/cloud/cloud-660ea483-4e48-41d4-882b-75df0b1da3bb"
    configpb_attributes      = []
    debugvrfcontext          = []
    id                       = "https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab"
    internal_gateway_monitor = []
    name                     = "vrf01"
    static_routes            = [
        {
            disable_gateway_monitor = ""
            if_name                 = ""
            labels                  = []
            next_hop                = [
                {
                    addr = "192.168.3.1"
                    type = "V4"
                },
            ]
            prefix                  = [
                {
                    ip_addr = [
                        {
                            addr = "0.0.0.0"
                            type = "V4"
                        },
                    ]
                    mask    = "0"
                },
            ]
            route_id                = "1"
        },
    ]
    tenant_ref               = "https://avi51.home.local/api/tenant/admin"
    uuid                     = "vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab"
}
terraform state show

「terraform state show」コマンドは、指定したリソースだけの情報を確認することができます。
例えば、VIPの情報だけ取得したい場合は、以下のようにコマンドを実行します。

PS C:\work\Terraform\alb>
PS C:\work\Terraform\alb> terraform state show avi_vsvip.vip01
# avi_vsvip.vip01:
resource "avi_vsvip" "vip01" {
    cloud_ref           = "https://avi51.home.local/api/cloud/cloud-660ea483-4e48-41d4-882b-75df0b1da3bb"
    east_west_placement = "false"
    id                  = "https://avi51.home.local/api/vsvip/vsvip-9ed7e1f9-1f0c-4d48-b04b-a56d53d4da7b"
    name                = "VIP_192.168.3.11"
    tenant_ref          = "https://avi51.home.local/api/tenant/admin"
    uuid                = "vsvip-9ed7e1f9-1f0c-4d48-b04b-a56d53d4da7b"
    vrf_context_ref     = "https://avi51.home.local/api/vrfcontext/vrfcontext-bf0c8942-5281-4505-8056-3b73119a0cab"

    vip {
        auto_allocate_floating_ip = "false"
        auto_allocate_ip          = "false"
        auto_allocate_ip_type     = "V4_ONLY"
        avi_allocated_fip         = "false"
        avi_allocated_vip         = "false"
        enabled                   = "true"
        prefix_length             = "32"
        vip_id                    = "0"

        ip_address {
            addr = "192.168.3.11"
            type = "V4"
        }
    }
}
PS C:\work\Terraform\alb> 
terraform fmt

「terraform fmt」コマンドは、コードの体裁を自動的に整えてくれます。
コマンド実行前後で比較してみましょう。

★コマンド実行前
resource "avi_vsvip" "vip01" {
  name             = "VIP_192.168.3.11"
  vip {
  vip_id = "0"
  ip_address {
  type = "V4"
  addr = "192.168.3.11"
  }
  auto_allocate_ip = false
  }
  tenant_ref      = data.avi_tenant.admin.id
  cloud_ref       = data.avi_cloud.default_cloud.id
  vrf_context_ref = data.avi_vrfcontext.vrf01.id
}

★コマンド実行後
resource "avi_vsvip" "vip01" {
  name = "VIP_192.168.3.11"
  vip {
    vip_id = "0"
    ip_address {
      type = "V4"
      addr = "192.168.3.11"
    }
    auto_allocate_ip = false
  }
  tenant_ref      = data.avi_tenant.admin.id
  cloud_ref       = data.avi_cloud.default_cloud.id
  vrf_context_ref = data.avi_vrfcontext.vrf01.id
}

私もTerraformを初めて1週間ですが、tfファイルの作成さえできてしまえば、コマンドの実行や切り戻しが非常に簡単で、かつコードの内容も理解がしやすいので、もっと早く身につけておけばよかったと思うほど便利です。
今回は、基本的なところの紹介でしたが、いろいろな製品でTerraformを利用していきたいと思います。
それでは、今回はこの辺で。