Terraform で ACI 上に L3out を含む Tenant を作成する
Terraform を使って Cisco ACI に「L3out を作成する」サンプルをメモしておきます。
構成
Terraform で以下の構成を設定します。
![file](01.png)
Terraform の設定ファイルは以下の通りです。
- variables.tf
- main.tf
- aci.tf
variables.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | 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_rest
に depends_on
で明示的に依存関係を定義しています。 また、Terraform で作成した Tenant を手動で作成すると terraform.tfstate
が意図しない内容で残ってしまうのか、それ以降 aci_rest
が上手く実行されなくなります。 こういった場合は「Tenant は terraform destroy
で削除する」か、または「terraform.tfstate
を手動で削除する」ことで回避出来るようです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 | # 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
}
|