Terraform で ACI 上に L3out を含む Tenant を作成する

Terraform を使って Cisco ACI に「L3out を作成する」サンプルをメモしておきます。

構成

Terraform で以下の構成を設定します。

file

Terraform の設定ファイル

Terraform の設定ファイルは以下の通りです。

  1. variables.tf
  2. main.tf
  3. aci.tf

variables.tf

variable "aci_url" { default = "https://10.0.0.1" }
variable "aci_username" { default = "admin" }
variable "aci_password" { default = "password" }
variable "tenant" { default = "Tenant1" }
variable "vrf" { default = "VRF" }
variable "contract1" { default = "CT" }

variable "l3dom" { default = "ExtRoutedDom" }
variable "l3out1" { default = "L3out" }
variable "lnode1_tdn" { default = "topology/pod-1/node-201" }
variable "lnode1_rtr_id" { default = "10.0.254.201" }
variable "lnode1_rtr_id_loop_back" { default = "no" }
variable "l3out1_att_addr" { default = "10.0.100.254/24" }
variable "l3out1_att_autostate" { default = "enabled" }
variable "l3out1_att_encap" { default = "vlan-100" }
variable "l3out1_att_ifInstT" { default = "ext-svi" }
variable "l3out1_att_mtu" { default = "1500" }
variable "l3out1_att_tDn" { default = "topology/pod-1/paths-201/pathep-[eth1/1]" }

variable "bd1" { default = "VL101_BD" }
variable "bd1_subnet" { default = "10.0.101.254/24" }
variable "ap1" { default = "AP" }
variable "physdom" { default = "PhysDom" }
variable "epg1" { default = "VL101_EPG" }
variable "egp1_port1_tdn" { default = "topology/pod-1/paths-201/pathep-[eth1/2]" }
variable "egp1_port1_vlan" { default = "vlan-101" }
variable "epg1_contract1_type" { default = "provider" }

main.tf

terraform {
  required_providers {
    aci = {
      source  = "CiscoDevNet/aci"
      version = "0.5.4"
    }
  }
}

provider "aci" {
  username = var.aci_username
  password = var.aci_password
  url      = var.aci_url
  insecure = true
}

aci.tf

現時点の Terraform には Logical Interface を定義する Resource が無い為、aci_rest Resource を使って REST API を呼び出します。 aci_rest を使うと Terraform が依存関係を自動解決出来なくなってしまう為、aci_restdepends_on で明示的に依存関係を定義しています。 また、Terraform で作成した Tenant を手動で作成すると terraform.tfstate が意図しない内容で残ってしまうのか、それ以降 aci_rest が上手く実行されなくなります。 こういった場合は「Tenant は terraform destroy で削除する」か、または「terraform.tfstate を手動で削除する」ことで回避出来るようです。

# Tenant
resource "aci_tenant" "tenant" {
  name = var.tenant
}

# VRF
resource "aci_vrf" "vrf" {
  tenant_dn = aci_tenant.tenant.id
  name      = var.vrf
}

# Contract / Subject / Filter
resource "aci_filter" "any" {
    tenant_dn = aci_tenant.tenant.id
    name      = "any_Filt"
}

resource "aci_filter_entry" "entry1" {
    name        = "0010"
    filter_dn   = aci_filter.any.id
    ether_t     = "unspecified"
}

resource "aci_contract" "contract1" {
    tenant_dn = aci_tenant.tenant.id
    name      = var.contract1
}

resource "aci_contract_subject" "subject1" {
    contract_dn                  = aci_contract.contract1.id
    name                         = "${var.contract1}_Subj"
    relation_vz_rs_subj_filt_att = [aci_filter.any.id]
}

# Domain
data "aci_l3_domain_profile" "l3dom" {
  name = var.l3dom
}

# L3Out
resource "aci_l3_outside" "l3out1" {
  tenant_dn                    = aci_tenant.tenant.id
  name                         = var.l3out1
  relation_l3ext_rs_ectx       = aci_vrf.vrf.id
  relation_l3ext_rs_l3_dom_att = data.aci_l3_domain_profile.l3dom.id
}

resource "aci_logical_node_profile" "lnprof1" {
  l3_outside_dn = aci_l3_outside.l3out1.id
  name          = "${var.l3out1}_NodeProf"
}

resource "aci_logical_node_to_fabric_node" "lnode1" {
  logical_node_profile_dn  = aci_logical_node_profile.lnprof1.id
  tdn                      = var.lnode1_tdn
  rtr_id                   = var.lnode1_rtr_id
  rtr_id_loop_back         = var.lnode1_rtr_id_loop_back
}

resource "aci_logical_interface_profile" "lifprof1" {
  logical_node_profile_dn = aci_logical_node_profile.lnprof1.id
  name                    = "${var.l3out1}_IntProf"
  relation_l3ext_rs_path_l3_out_att = toset([var.l3out1_att_tDn])
}

resource "aci_rest" "l3out1_att" {
  path       = "/api/mo/uni/tn-${var.tenant}/out-${aci_l3_outside.l3out1.name}/lnodep-${aci_logical_node_profile.lnprof1.name}/lifp-${aci_logical_interface_profile.lifprof1.name}.json"
  class_name = "l3extRsPathL3OutAtt"
  content = {
    "addr"      = var.l3out1_att_addr
    "autostate" = var.l3out1_att_autostate
    "encap"     = var.l3out1_att_encap
    "ifInstT"   = var.l3out1_att_ifInstT
    "mtu"       = var.l3out1_att_mtu
    "tDn"       = var.l3out1_att_tDn
  }
  depends_on = [
    aci_logical_interface_profile.lifprof1,
  ]
}

# L3Out1 External EPG
resource "aci_external_network_instance_profile" "l3out1_epg1" {
  l3_outside_dn       = aci_l3_outside.l3out1.id
  name                = "${var.l3out1}_L3PEG"
  relation_fv_rs_cons = [aci_contract.contract1.id]
}

resource "aci_l3_ext_subnet" "l3out1_subnet1" {
  external_network_instance_profile_dn = aci_external_network_instance_profile.l3out1_epg1.id
  ip                                   = "0.0.0.0/0"
  scope                                = ["import-security"]
}

# BD1
resource "aci_bridge_domain" "bd1" {
  tenant_dn          = aci_tenant.tenant.id
  name               = var.bd1
  relation_fv_rs_ctx = aci_vrf.vrf.id
}

resource "aci_subnet" "bd1_subnet" {
  parent_dn = aci_bridge_domain.bd1.id
  ip        = var.bd1_subnet
}

# Application Profile
resource "aci_application_profile" "ap1" {
  tenant_dn = aci_tenant.tenant.id
  name      = var.ap1
}

# Domain
data "aci_physical_domain" "physdom" {
  name = var.physdom
}

# EPG1
resource "aci_application_epg" "epg1" {
  application_profile_dn = aci_application_profile.ap1.id
  name                   = var.epg1
  relation_fv_rs_bd      = aci_bridge_domain.bd1.id
}

resource "aci_epg_to_domain" "epg1_physdom" {
  application_epg_dn = aci_application_epg.epg1.id
  tdn                = data.aci_physical_domain.physdom.id
}

resource "aci_epg_to_static_path" "egp1_port1" {
  application_epg_dn = aci_application_epg.epg1.id
  tdn                = var.egp1_port1_tdn
  encap              = var.egp1_port1_vlan
}

resource "aci_epg_to_contract" "epg1_contract1" {
    application_epg_dn = aci_application_epg.epg1.id
    contract_dn        = aci_contract.contract1.id
    contract_type      = var.epg1_contract1_type
}

コメント

タイトルとURLをコピーしました