This is an automated email from the ASF dual-hosted git repository.

Pearl1594 pushed a commit to branch support-internal-lb
in repository 
https://gitbox.apache.org/repos/asf/cloudstack-terraform-provider.git

commit 93148a011712517785c5953461168124f4e0bfcd
Author: Pearl Dsilva <[email protected]>
AuthorDate: Fri Aug 14 14:06:41 2026 -0400

    Add support for internal LB
---
 .../resource_cloudstack_loadbalancer_rule.go       | 29 ++++++++--
 .../resource_cloudstack_loadbalancer_rule_test.go  | 66 ++++++++++++++++++++++
 2 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/cloudstack/resource_cloudstack_loadbalancer_rule.go 
b/cloudstack/resource_cloudstack_loadbalancer_rule.go
index 6ebf52b..b15200e 100644
--- a/cloudstack/resource_cloudstack_loadbalancer_rule.go
+++ b/cloudstack/resource_cloudstack_loadbalancer_rule.go
@@ -50,9 +50,14 @@ func resourceCloudStackLoadBalancerRule() *schema.Resource {
                                Computed: true,
                        },
 
+                       // Optional, not Required: CloudStack's own 
createLoadBalancerRule
+                       // marks publicipid as optional -- an internal LB in a 
VPC (no
+                       // public IP at all, just network_id) is a real, 
supported case.
+                       // See verifyLoadBalancerRule, which enforces that at 
least one of
+                       // ip_address_id/network_id is set instead.
                        "ip_address_id": {
                                Type:     schema.TypeString,
-                               Required: true,
+                               Optional: true,
                                ForceNew: true,
                        },
 
@@ -163,8 +168,12 @@ func resourceCloudStackLoadBalancerRuleCreate(d 
*schema.ResourceData, meta inter
                p.SetCidrlist(cidrList)
        }
 
-       // Set the ipaddress id
-       p.SetPublicipid(d.Get("ip_address_id").(string))
+       // Set the ipaddress id, when given -- omitted entirely for an internal
+       // LB (network_id-only, no public IP), matching real CloudStack's own
+       // optional publicipid semantics.
+       if ipAddressID, ok := d.GetOk("ip_address_id"); ok {
+               p.SetPublicipid(ipAddressID.(string))
+       }
 
        // Create the load balancer rule
        r, err := cs.LoadBalancer.CreateLoadBalancerRule(p)
@@ -230,7 +239,13 @@ func resourceCloudStackLoadBalancerRuleRead(d 
*schema.ResourceData, meta interfa
        }
 
        d.Set("name", lb.Name)
-       d.Set("ip_address_id", lb.Publicipid)
+       // Only set ip_address_id if the user specified it, mirroring 
network_id's
+       // own guard below -- an internal LB's lb.Publicipid comes back empty
+       // from CloudStack, and setting that explicitly would fight the schema's
+       // Optional (no Computed) declaration.
+       if _, ok := d.GetOk("ip_address_id"); ok {
+               d.Set("ip_address_id", lb.Publicipid)
+       }
        d.Set("algorithm", lb.Algorithm)
        d.Set("public_port", public_port)
        d.Set("private_port", private_port)
@@ -534,6 +549,12 @@ func resourceCloudStackLoadBalancerRuleDelete(d 
*schema.ResourceData, meta inter
 }
 
 func verifyLoadBalancerRule(d *schema.ResourceData) error {
+       _, hasIP := d.GetOk("ip_address_id")
+       _, hasNetwork := d.GetOk("network_id")
+       if !hasIP && !hasNetwork {
+               return fmt.Errorf("at least one of ip_address_id or network_id 
must be set")
+       }
+
        if protocol, ok := d.GetOk("protocol"); ok {
                protocol := protocol.(string)
 
diff --git a/cloudstack/resource_cloudstack_loadbalancer_rule_test.go 
b/cloudstack/resource_cloudstack_loadbalancer_rule_test.go
index 8a9c792..ab24f60 100644
--- a/cloudstack/resource_cloudstack_loadbalancer_rule_test.go
+++ b/cloudstack/resource_cloudstack_loadbalancer_rule_test.go
@@ -210,6 +210,36 @@ func TestAccCloudStackLoadBalancerRule_vpcUpdate(t 
*testing.T) {
        })
 }
 
+// TestAccCloudStackLoadBalancerRule_internal exercises a pure internal LB:
+// network_id set, ip_address_id omitted entirely -- no public IP at all.
+// Real CloudStack's createLoadBalancerRule marks publicipid optional for
+// exactly this VPC-internal case; before this fix the schema's
+// Required:true on ip_address_id made it impossible to even plan such a
+// config, regardless of what the real API allowed.
+func TestAccCloudStackLoadBalancerRule_internal(t *testing.T) {
+       resource.Test(t, resource.TestCase{
+               PreCheck:     func() { testAccPreCheck(t) },
+               Providers:    testAccProviders,
+               CheckDestroy: testAccCheckCloudStackLoadBalancerRuleDestroy,
+               Steps: []resource.TestStep{
+                       {
+                               Config: 
testAccCloudStackLoadBalancerRule_internal,
+                               Check: resource.ComposeTestCheckFunc(
+                                       
testAccCheckCloudStackLoadBalancerRuleExist("cloudstack_loadbalancer_rule.foo", 
nil),
+                                       resource.TestCheckResourceAttr(
+                                               
"cloudstack_loadbalancer_rule.foo", "name", "terraform-ilb"),
+                                       resource.TestCheckResourceAttr(
+                                               
"cloudstack_loadbalancer_rule.foo", "ip_address_id", ""),
+                                       resource.TestCheckResourceAttr(
+                                               
"cloudstack_loadbalancer_rule.foo", "public_port", "8080"),
+                                       resource.TestCheckResourceAttr(
+                                               
"cloudstack_loadbalancer_rule.foo", "private_port", "8080"),
+                               ),
+                       },
+               },
+       })
+}
+
 func testAccCheckCloudStackLoadBalancerRuleExist(n string, id *string) 
resource.TestCheckFunc {
        return func(s *terraform.State) error {
                rs, ok := s.RootModule().Resources[n]
@@ -466,3 +496,39 @@ resource "cloudstack_loadbalancer_rule" "foo" {
   member_ids = [cloudstack_instance.foobar1.id, cloudstack_instance.foobar2.id]
   cidrlist = ["20.0.0.0/8"]
 }`
+
+const testAccCloudStackLoadBalancerRule_internal = `
+resource "cloudstack_vpc" "foo" {
+  name = "terraform-vpc"
+  cidr = "10.0.0.0/8"
+  vpc_offering = "Default VPC offering"
+  zone = "Sandbox-simulator"
+}
+
+resource "cloudstack_network" "foo" {
+  name = "terraform-network"
+  display_text = "terraform-network"
+  cidr = "10.1.1.0/24"
+  network_offering = "DefaultIsolatedNetworkOfferingForVpcNetworks"
+  vpc_id = cloudstack_vpc.foo.id
+  zone = cloudstack_vpc.foo.zone
+}
+
+resource "cloudstack_instance" "foobar1" {
+  name = "terraform-server1"
+  display_name = "terraform"
+  service_offering= "Small Instance"
+  network_id = cloudstack_network.foo.id
+  template = "CentOS 5.6 (64-bit) no GUI (Simulator)"
+  zone = cloudstack_network.foo.zone
+  expunge = true
+}
+
+resource "cloudstack_loadbalancer_rule" "foo" {
+  name = "terraform-ilb"
+  algorithm = "roundrobin"
+  network_id = cloudstack_network.foo.id
+  public_port = 8080
+  private_port = 8080
+  member_ids = [cloudstack_instance.foobar1.id]
+}`

Reply via email to