Terraform を使って Cisco ACI に「OSPF 設定の L3out を作成する」サンプルをメモしておきます。
構成
Terraform で以下の構成を設定します。
Terraform の設定ファイル
Terraform の設定ファイルは以下の通りです。
- variables.tf
- main.tf
- 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 "l3out1_ospf_area" { default = "0.0.0.0" }
variable "l3out1_lnode1_tdn" { default = "topology/pod-1/node-201" }
variable "l3out1_lnode1_rtr_id" { default = "10.0.254.201" }
variable "l3out1_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 が有りませんが、同様に L3out に関する OSPF 設定も Resource が存在しません (※ OSPF Interface Policy は存在します)。 その為、L3out へ OSPF 設定を関連付ける部分は aci_rest
を用いて設定します。
# 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]
}
# OSPF Interface Policy
resource "aci_ospf_interface_policy" "ospf_if" {
tenant_dn = aci_tenant.tenant.id
name = "Point-to-Point"
cost = "unspecified"
nw_t = "p2p"
prio = "1"
#ctrl = ""
pfx_suppress = "inherit"
hello_intvl = "10"
dead_intvl = "40"
rexmit_intvl = "5"
xmit_delay = "1"
}
# 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_rest" "l3out1_ospf" {
path = "/api/mo/uni/tn-${var.tenant}/out-${aci_l3_outside.l3out1.name}.json"
class_name = "ospfExtP"
content = {
"areaType" = "regular"
"areaCost" = "1"
"areaId" = var.l3out1_ospf_area
"areaCtrl" = "redistribute,summary"
}
depends_on = [aci_l3_outside.l3out1]
}
resource "aci_logical_node_profile" "l3out1_lnprof1" {
l3_outside_dn = aci_l3_outside.l3out1.id
name = "${var.l3out1}_NodeProf"
}
resource "aci_logical_node_to_fabric_node" "l3out1_lnode1" {
logical_node_profile_dn = aci_logical_node_profile.l3out1_lnprof1.id
tdn = var.l3out1_lnode1_tdn
rtr_id = var.l3out1_lnode1_rtr_id
rtr_id_loop_back = var.l3out1_lnode1_rtr_id_loop_back
}
resource "aci_logical_interface_profile" "l3out1_lifprof1" {
logical_node_profile_dn = aci_logical_node_profile.l3out1_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.l3out1_lnprof1.name}/lifp-${aci_logical_interface_profile.l3out1_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.l3out1_lifprof1]
}
resource "aci_rest" "l3out1_att_ospf" {
path = "/api/mo/uni/tn-${var.tenant}/out-${aci_l3_outside.l3out1.name}/lnodep-${aci_logical_node_profile.l3out1_lnprof1.name}/lifp-${aci_logical_interface_profile.l3out1_lifprof1.name}.json"
class_name = "ospfIfP"
content = {
"authKeyId" = "1"
"authType" = "none"
}
depends_on = [aci_rest.l3out1_att]
}
resource "aci_rest" "l3out1_att_ospfpol" {
path = "/api/mo/uni/tn-${var.tenant}/out-${aci_l3_outside.l3out1.name}/lnodep-${aci_logical_node_profile.l3out1_lnprof1.name}/lifp-${aci_logical_interface_profile.l3out1_lifprof1.name}/ospfIfP.json"
class_name = "ospfRsIfPol"
content = {
"tnOspfIfPolName" = aci_ospf_interface_policy.ospf_if.name
}
depends_on = [aci_rest.l3out1_att_ospf]
}
# 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
relation_fv_rs_bd_to_out = [aci_l3_outside.l3out1.id]
}
resource "aci_subnet" "bd1_subnet" {
parent_dn = aci_bridge_domain.bd1.id
ip = var.bd1_subnet
scope = ["public"]
}
# 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
}
コメント