From 48ee45596333e106fd777de69e1437990a351db3 Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 30 Sep 2025 06:42:55 -0400 Subject: [PATCH 1/5] first attempt --- cloudstack/resource_cloudstack_network.go | 118 ++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/cloudstack/resource_cloudstack_network.go b/cloudstack/resource_cloudstack_network.go index e7329f82..ee462196 100644 --- a/cloudstack/resource_cloudstack_network.go +++ b/cloudstack/resource_cloudstack_network.go @@ -78,6 +78,12 @@ func resourceCloudStackNetwork() *schema.Resource { ForceNew: true, }, + "ip6cidr": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "gateway": { Type: schema.TypeString, Optional: true, @@ -85,6 +91,13 @@ func resourceCloudStackNetwork() *schema.Resource { ForceNew: true, }, + "ip6gateway": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "startip": { Type: schema.TypeString, Optional: true, @@ -99,6 +112,20 @@ func resourceCloudStackNetwork() *schema.Resource { ForceNew: true, }, + "startipv6": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "endipv6": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "network_domain": { Type: schema.TypeString, Optional: true, @@ -209,6 +236,32 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e p.SetEndip(endip) } + m, err := parseCIDRv6(d, no.Specifyipranges) + if err != nil { + return err + } + + if m != nil { + if ip6cidr, ok := m["ip6cidr"]; ok { + p.SetIp6cidr(ip6cidr) + } + + // Only set the start IPv6 if we have one + if startipv6, ok := m["startipv6"]; ok { + p.SetStartipv6(startipv6) + } + + // Only set the ipv6 gateway if we have one + if ip6gateway, ok := m["ip6gateway"]; ok { + p.SetIp6Gateway(ip6gateway) + } + + // Only set the end IPv6 if we have one + if endipv6, ok := m["endipv6"]; ok { + p.SetEndipv6(endipv6) + } + } + // Set the network domain if we have one if networkDomain, ok := d.GetOk("network_domain"); ok { p.SetNetworkdomain(networkDomain.(string)) @@ -306,6 +359,16 @@ func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) err d.Set("network_domain", n.Networkdomain) d.Set("vpc_id", n.Vpcid) + if n.Ip6cidr = "" { + n.Ip6cidr = none + } + d.Set("ip6cidr", n.Ip6cidr) + + if n.Ip6gateway = "" { + n.Ip6gateway = none + } + d.Set("ip6gateway", n.Ip6gateway) + if n.Aclid == "" { n.Aclid = none } @@ -371,6 +434,11 @@ func resourceCloudStackNetworkUpdate(d *schema.ResourceData, meta interface{}) e p.SetGuestvmcidr(d.Get("cidr").(string)) } + // Check if the ip6cidr is changed + if d.HasChange("ip6cidr") { + p.SetGuestvmip6cidr(d.Get("ip6cidr").(string)) + } + // Check if the network domain is changed if d.HasChange("network_domain") { p.SetNetworkdomain(d.Get("network_domain").(string)) @@ -471,3 +539,53 @@ func parseCIDR(d *schema.ResourceData, specifyiprange bool) (map[string]string, return m, nil } + +func parseCIDRv6(d *schema.ResourceData, specifyiprange bool) (map[string]string, error) { + m := make(map[string]string, 4) + + cidr := d.Get("ip6cidr").(string) + ip, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("Unable to parse cidr %s: %s", cidr, err) + } + + if gateway, ok := d.GetOk("ip6gateway"); ok { + m["ip6gateway"] = gateway.(string) + } else { + m["ip6gateway"] = ipnet.IP + } + + if startip, ok := d.GetOk("startip"); ok { + m["startip"] = startip.(string) + } else if specifyiprange { + ip16 := ipnet.IP.To16() + if ip16 == nil { + return nil, fmt.Errorf("cidr not valid for ipv6") + } + + myip := make(net.IP, len(ip16)) + copy(myip, ip16) + myip[range ip16 - 1] = 2; + m["startip"] = myip.String() + } + + if endip, ok := d.GetOk("endipv6"); ok { + m["endipv6"] = endip.(string) + } else if specifyiprange { + ip16 := ipnet.IP.To16() + if ip16 == nil { + return nil, fmt.Errorf("cidr not valid for ipv6") + } + + last := make(net.IP, len(ip16)) + copy(last, ip16) + + for i := range ip16 { + // Perform bitwise OR with the inverse of the mask + last[i] |= ^ipnet.Mask[i] + } + m["endipv6"] = last.String() + } + + return m, nil +} From 10d52f5d6fc008d39917b9bcc207501f0f9ae2bc Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 30 Sep 2025 07:09:30 -0400 Subject: [PATCH 2/5] fixes --- cloudstack/resource_cloudstack_network.go | 29 ++++++++++------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/cloudstack/resource_cloudstack_network.go b/cloudstack/resource_cloudstack_network.go index ee462196..8f0e093e 100644 --- a/cloudstack/resource_cloudstack_network.go +++ b/cloudstack/resource_cloudstack_network.go @@ -236,28 +236,28 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e p.SetEndip(endip) } - m, err := parseCIDRv6(d, no.Specifyipranges) + m6, err := parseCIDRv6(d, no.Specifyipranges) if err != nil { return err } - if m != nil { - if ip6cidr, ok := m["ip6cidr"]; ok { + if m6 != nil { + if ip6cidr, ok := m6["ip6cidr"]; ok { p.SetIp6cidr(ip6cidr) } // Only set the start IPv6 if we have one - if startipv6, ok := m["startipv6"]; ok { + if startipv6, ok := m6["startipv6"]; ok { p.SetStartipv6(startipv6) } // Only set the ipv6 gateway if we have one - if ip6gateway, ok := m["ip6gateway"]; ok { - p.SetIp6Gateway(ip6gateway) + if ip6gateway, ok := m6["ip6gateway"]; ok { + p.SetIp6gateway(ip6gateway) } // Only set the end IPv6 if we have one - if endipv6, ok := m["endipv6"]; ok { + if endipv6, ok := m6["endipv6"]; ok { p.SetEndipv6(endipv6) } } @@ -359,12 +359,12 @@ func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) err d.Set("network_domain", n.Networkdomain) d.Set("vpc_id", n.Vpcid) - if n.Ip6cidr = "" { + if n.Ip6cidr == "" { n.Ip6cidr = none } d.Set("ip6cidr", n.Ip6cidr) - if n.Ip6gateway = "" { + if n.Ip6gateway == "" { n.Ip6gateway = none } d.Set("ip6gateway", n.Ip6gateway) @@ -434,11 +434,6 @@ func resourceCloudStackNetworkUpdate(d *schema.ResourceData, meta interface{}) e p.SetGuestvmcidr(d.Get("cidr").(string)) } - // Check if the ip6cidr is changed - if d.HasChange("ip6cidr") { - p.SetGuestvmip6cidr(d.Get("ip6cidr").(string)) - } - // Check if the network domain is changed if d.HasChange("network_domain") { p.SetNetworkdomain(d.Get("network_domain").(string)) @@ -544,7 +539,7 @@ func parseCIDRv6(d *schema.ResourceData, specifyiprange bool) (map[string]string m := make(map[string]string, 4) cidr := d.Get("ip6cidr").(string) - ip, ipnet, err := net.ParseCIDR(cidr) + _, ipnet, err := net.ParseCIDR(cidr) if err != nil { return nil, fmt.Errorf("Unable to parse cidr %s: %s", cidr, err) } @@ -552,7 +547,7 @@ func parseCIDRv6(d *schema.ResourceData, specifyiprange bool) (map[string]string if gateway, ok := d.GetOk("ip6gateway"); ok { m["ip6gateway"] = gateway.(string) } else { - m["ip6gateway"] = ipnet.IP + m["ip6gateway"] = ipnet.IP.String() } if startip, ok := d.GetOk("startip"); ok { @@ -565,7 +560,7 @@ func parseCIDRv6(d *schema.ResourceData, specifyiprange bool) (map[string]string myip := make(net.IP, len(ip16)) copy(myip, ip16) - myip[range ip16 - 1] = 2; + myip[len(ip16)-1] = 2 m["startip"] = myip.String() } From d10b052aeea4f2695c3313f391c48b5295e33a69 Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 30 Sep 2025 13:17:50 -0400 Subject: [PATCH 3/5] fix --- cloudstack/resource_cloudstack_network.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cloudstack/resource_cloudstack_network.go b/cloudstack/resource_cloudstack_network.go index 8f0e093e..8037cd2a 100644 --- a/cloudstack/resource_cloudstack_network.go +++ b/cloudstack/resource_cloudstack_network.go @@ -236,12 +236,13 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e p.SetEndip(endip) } - m6, err := parseCIDRv6(d, no.Specifyipranges) - if err != nil { - return err - } + // IPv6 support + if _, ok := d.GetOk("ip6cidr"); ok { + m6, err := parseCIDRv6(d, no.Specifyipranges) + if err != nil { + return err + } - if m6 != nil { if ip6cidr, ok := m6["ip6cidr"]; ok { p.SetIp6cidr(ip6cidr) } From 23351578cb9a5bad2d19ccd851e439f28cabd348 Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 30 Sep 2025 13:25:43 -0400 Subject: [PATCH 4/5] docs --- website/docs/r/network.html.markdown | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/website/docs/r/network.html.markdown b/website/docs/r/network.html.markdown index d83ebb1a..528ae681 100644 --- a/website/docs/r/network.html.markdown +++ b/website/docs/r/network.html.markdown @@ -43,6 +43,18 @@ The following arguments are supported: * `endip` - (Optional) End of the IP block that will be available on the network. Defaults to the last available IP in the range. +* `ip6cidr` - (Optional) The IPv6 CIDR block for the network. Changing this + forces a new resource to be created. + +* `ip6gateway` - (Optional) IPv6 Gateway that will be provided to the instances + in this network. Defaults to the first usable IP in the range. + +* `startipv6` - (Optional) Start of the IPv6 block that will be available on the + network. Defaults to the second available IP in the range. + +* `endipv6` - (Optional) End of the IPv6 block that will be available on the + network. Defaults to the last available IP in the range. + * `network_domain` - (Optional) DNS domain for the network. * `network_offering` - (Required) The name or ID of the network offering to use From 7dc3bc768cf39fe5bae10718cc4dd71f32da6ad3 Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 30 Sep 2025 14:40:57 -0400 Subject: [PATCH 5/5] ignore blank ip6cidr --- cloudstack/resource_cloudstack_network.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cloudstack/resource_cloudstack_network.go b/cloudstack/resource_cloudstack_network.go index 8037cd2a..2adb21a3 100644 --- a/cloudstack/resource_cloudstack_network.go +++ b/cloudstack/resource_cloudstack_network.go @@ -237,15 +237,13 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e } // IPv6 support - if _, ok := d.GetOk("ip6cidr"); ok { + if ip6cidr, ok := d.GetOk("ip6cidr"); ok && ip6cidr.(string) != none { m6, err := parseCIDRv6(d, no.Specifyipranges) if err != nil { return err } - if ip6cidr, ok := m6["ip6cidr"]; ok { - p.SetIp6cidr(ip6cidr) - } + p.SetIp6cidr(ip6cidr) // Only set the start IPv6 if we have one if startipv6, ok := m6["startipv6"]; ok {