Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Network resource to use custom templates #121

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion dcnm/data_source_dcnm_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ func datasourceDCNMNetwork() *schema.Resource {
Computed: true,
},

"template_props": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"source": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -273,7 +279,11 @@ func datasourceDCNMNetworkRead(d *schema.ResourceData, m interface{}) error {
return err
}

setNetworkAttributes(d, cont)
if stripQuotes(cont.S("networkTemplate").String()) != "Default_Network_Universal" {
setNetworkCustomTemplateAttributes(d, cont)
} else {
setNetworkAttributes(d, cont)
}

deployed, err := checkNetworkDeploy(dcnmClient, fabricName, name)
if err != nil {
Expand Down
112 changes: 98 additions & 14 deletions dcnm/resource_dcnm_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ func resourceDCNMNetwork() *schema.Resource {
Computed: true,
},

"template_props": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"source": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -483,6 +489,52 @@ func setNetworkAttributes(d *schema.ResourceData, cont *container.Container) *sc
return d
}

func setNetworkCustomTemplateAttributes(d *schema.ResourceData, cont *container.Container) *schema.ResourceData {
if cont.Exists("fabric") {
d.Set("fabric_name", stripQuotes(cont.S("fabric").String()))
}
d.Set("fabric_name", stripQuotes(cont.S("fabric").String()))
d.Set("name", stripQuotes(cont.S("networkName").String()))
d.Set("network_id", stripQuotes(cont.S("networkId").String()))
d.Set("template", stripQuotes(cont.S("networkTemplate").String()))
d.Set("extension_template", stripQuotes(cont.S("networkExtensionTemplate").String()))
d.Set("vrf_name", stripQuotes(cont.S("vrf").String()))

if cont.Exists("displayName") {
d.Set("display_name", stripQuotes(cont.S("displayName").String()))
}
if cont.Exists("serviceNetworkTemplate") && stripQuotes(cont.S("serviceNetworkTemplate").String()) != "null" {
d.Set("service_template", stripQuotes(cont.S("serviceNetworkTemplate").String()))
}
if cont.Exists("source") && stripQuotes(cont.S("source").String()) != "null" {
d.Set("source", stripQuotes(cont.S("source").String()))
}

var strByte []byte
if cont.Exists("networkTemplateConfig") {
strJson := models.G(cont, "networkTemplateConfig")
strJson = strings.ReplaceAll(strJson, "\\", "")
strByte = []byte(strJson)
var networkTemplateConfig map[string]string
json.Unmarshal(strByte, &networkTemplateConfig)
props, ok := d.GetOk("template_props")

map2 := make(map[string]interface{})
for k := range props.(map[string]interface{}) {
map2[k] = networkTemplateConfig[k]
}
if !ok {
d.Set("template_props", networkTemplateConfig)
} else {

d.Set("template_props", map2)
}
}

d.SetId(stripQuotes(cont.S("networkName").String()))
return d
}

func resourceDCNMNetworkImporter(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
log.Println("[DEBUG] Begining Importer ", d.Id())

Expand All @@ -499,7 +551,12 @@ func resourceDCNMNetworkImporter(d *schema.ResourceData, m interface{}) ([]*sche
return nil, err
}

stateImport := setNetworkAttributes(d, cont)
var stateImport *schema.ResourceData
if stripQuotes(cont.S("networkTemplate").String()) != "Default_Network_Universal" {
stateImport = setNetworkCustomTemplateAttributes(d, cont)
} else {
stateImport = setNetworkAttributes(d, cont)
}

deployed, err := checkNetworkDeploy(dcnmClient, fabricName, network)
if err != nil {
Expand Down Expand Up @@ -718,14 +775,26 @@ func resourceDCNMNetworkCreate(d *schema.ResourceData, m interface{}) error {
} else {
networkProfile.NVEId = ""
}
networkProfile.NetworkName = name
networkProfile.SegmentID = segID

configStr, err := json.Marshal(networkProfile)
if err != nil {
return err
if networkConfig, ok := d.GetOk("template_props"); ok {
networkConfigMap := networkConfig.(map[string]interface{})
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we should assign the values in the key template_props directly without any further verification. I would argue that users setting the key template_props must be completely sure that the JSON payload is built based on those values without further verification

Maybe we should only check if the VLAN ID and the Multicast group are part of the keys. If not we generate them. What are your thoughts?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having a check to ensure the template_props are verified is a good step to add. Yes, i think VLAN ID and multicast group are a good start. I'll think more about what other parameters are important.

networkConfigMap["networkName"] = name
networkConfigMap["segmentId"] = segID
networkConfigMap["vrfName"] = network.VRF
confStr, err := json.Marshal(networkConfigMap)
if err != nil {
return err
}
network.Config = string(confStr)
} else {
networkProfile.NetworkName = network.Name
networkProfile.SegmentID = segID
confStr, err := json.Marshal(networkProfile)
if err != nil {
return err
}
network.Config = string(confStr)
}
network.Config = string(configStr)

durl := fmt.Sprintf("/rest/top-down/fabrics/%s/networks", fabricName)
_, err = dcnmClient.Save(durl, &network)
Expand Down Expand Up @@ -1023,14 +1092,25 @@ func resourceDCNMNetworkUpdate(d *schema.ResourceData, m interface{}) error {
} else {
networkProfile.NVEId = ""
}
networkProfile.NetworkName = name
networkProfile.SegmentID = segID

configStr, err := json.Marshal(networkProfile)
if err != nil {
return err
if networkConfig, ok := d.GetOk("template_props"); ok {
networkConfigMap := networkConfig.(map[string]interface{})
networkConfigMap["networkName"] = name
networkConfigMap["segmentId"] = segID
confStr, err := json.Marshal(networkConfigMap)
if err != nil {
return err
}
network.Config = string(confStr)
} else {
networkProfile.NetworkName = network.Name
networkProfile.SegmentID = segID
confStr, err := json.Marshal(networkProfile)
if err != nil {
return err
}
network.Config = string(confStr)
}
network.Config = string(configStr)

dn := d.Id()
durl := fmt.Sprintf("/rest/top-down/fabrics/%s/networks/%s", fabricName, dn)
Expand Down Expand Up @@ -1172,7 +1252,11 @@ func resourceDCNMNetworkRead(d *schema.ResourceData, m interface{}) error {
return err
}

setNetworkAttributes(d, cont)
if _, ok := d.GetOk("template_props"); ok {
setNetworkCustomTemplateAttributes(d, cont)
} else {
setNetworkAttributes(d, cont)
}

deployed, err := checkNetworkDeploy(dcnmClient, fabricName, dn)
if err != nil {
Expand Down
35 changes: 35 additions & 0 deletions examples/network/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,38 @@ resource "dcnm_network" "first" {
"Ethernet1/2"]
}
}

resource "dcnm_network" "second" {
fabric_name = "fab3"
name = "second"
network_id = "1235"
display_name = "second"
vrf_name = "VRF1012"
template = "Template_Universal"
extension_template = "Template_Extension_Universal"
template_props = {
"suppressArp" : "true"
"gatewayIpAddress" : "10.0.4.1/24"
"enableL3OnBorder" : "false"
"vlanName" : "first"
"enableIR" : "false"
"mtu" : "1500"
"rtBothAuto" : "false"
"isLayer2Only" : "false"
"mcastGroup" : "225.0.0.1"
"vrfDhcp2" : "VRF1000"
"dhcpServerAddr1" : "10.1.1.1"
"dhcpServerAddr2" : "10.1.1.2"
"vrfDhcp" : "VRF1000"
"tag" : ""
"vlanId" : "2303"
"networkName" : "second"
"segmentId" : "1235"
"vrfName" : "VRF1012"
}
deploy = true
attachments {
serial_number = dcnm_inventory.example3.serial_number
switch_ports = ["Ethernet1/22"]
}
}