Skip to content

Commit 1914ee1

Browse files
feat: Add automatic project inheritance for cloudstack_ipaddress from VPC or network
Implement automatic project inheritance for cloudstack_ipaddress resource: - IP address inherits project from vpc_id when no explicit project is set - IP address inherits project from network_id when no explicit project is set - Uses projectid=-1 for universal VPC/network lookup across projects - Updates state with inherited project during read operations Changes: - Modified resourceCloudStackIPAddressCreate to fetch VPC/network and inherit project - Modified resourceCloudStackIPAddressRead to handle universal project search - Added TestAccCloudStackIPAddress_vpcProjectInheritance test case - Added TestAccCloudStackIPAddress_networkProjectInheritance test case - Updated documentation with inheritance behavior and examples All 5 IP address acceptance tests passing.
1 parent c610f49 commit 1914ee1

File tree

3 files changed

+168
-1
lines changed

3 files changed

+168
-1
lines changed

cloudstack/resource_cloudstack_ipaddress.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,33 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{})
102102
if vpcid, ok := d.GetOk("vpc_id"); ok && vpcid.(string) != "" {
103103
return fmt.Errorf("set only network_id or vpc_id")
104104
}
105+
106+
// If no project is explicitly set, try to inherit it from the network
107+
if _, ok := d.GetOk("project"); !ok {
108+
// Get the network to retrieve its project
109+
// Use projectid=-1 to search across all projects
110+
network, count, err := cs.Network.GetNetworkByID(networkid.(string), cloudstack.WithProject("-1"))
111+
if err == nil && count > 0 && network.Projectid != "" {
112+
log.Printf("[DEBUG] Inheriting project %s from network %s", network.Projectid, networkid.(string))
113+
p.SetProjectid(network.Projectid)
114+
}
115+
}
105116
}
106117

107118
if vpcid, ok := d.GetOk("vpc_id"); ok {
108119
// Set the vpcid
109120
p.SetVpcid(vpcid.(string))
121+
122+
// If no project is explicitly set, try to inherit it from the VPC
123+
if _, ok := d.GetOk("project"); !ok {
124+
// Get the VPC to retrieve its project
125+
// Use projectid=-1 to search across all projects
126+
vpc, count, err := cs.VPC.GetVPCByID(vpcid.(string), cloudstack.WithProject("-1"))
127+
if err == nil && count > 0 && vpc.Projectid != "" {
128+
log.Printf("[DEBUG] Inheriting project %s from VPC %s", vpc.Projectid, vpcid.(string))
129+
p.SetProjectid(vpc.Projectid)
130+
}
131+
}
110132
}
111133

112134
if zone, ok := d.GetOk("zone"); ok {
@@ -121,6 +143,7 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{})
121143
}
122144

123145
// If there is a project supplied, we retrieve and set the project id
146+
// This will override the inherited project from VPC or network if explicitly set
124147
if err := setProjectid(p, cs, d); err != nil {
125148
return err
126149
}
@@ -150,6 +173,7 @@ func resourceCloudStackIPAddressRead(d *schema.ResourceData, meta interface{}) e
150173
d.Id(),
151174
cloudstack.WithProject(d.Get("project").(string)),
152175
)
176+
153177
if err != nil {
154178
if count == 0 {
155179
log.Printf(

cloudstack/resource_cloudstack_ipaddress_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,52 @@ func TestAccCloudStackIPAddress_vpcid_with_network_id(t *testing.T) {
8484
})
8585
}
8686

87+
func TestAccCloudStackIPAddress_vpcProjectInheritance(t *testing.T) {
88+
var ipaddr cloudstack.PublicIpAddress
89+
90+
resource.Test(t, resource.TestCase{
91+
PreCheck: func() { testAccPreCheck(t) },
92+
Providers: testAccProviders,
93+
CheckDestroy: testAccCheckCloudStackIPAddressDestroy,
94+
Steps: []resource.TestStep{
95+
{
96+
Config: testAccCloudStackIPAddress_vpcProjectInheritance,
97+
Check: resource.ComposeTestCheckFunc(
98+
testAccCheckCloudStackIPAddressExists(
99+
"cloudstack_ipaddress.foo", &ipaddr),
100+
// Verify the project was inherited from the VPC
101+
resource.TestCheckResourceAttr(
102+
"cloudstack_ipaddress.foo", "project", "terraform"),
103+
testAccCheckCloudStackIPAddressProjectInherited(&ipaddr),
104+
),
105+
},
106+
},
107+
})
108+
}
109+
110+
func TestAccCloudStackIPAddress_networkProjectInheritance(t *testing.T) {
111+
var ipaddr cloudstack.PublicIpAddress
112+
113+
resource.Test(t, resource.TestCase{
114+
PreCheck: func() { testAccPreCheck(t) },
115+
Providers: testAccProviders,
116+
CheckDestroy: testAccCheckCloudStackIPAddressDestroy,
117+
Steps: []resource.TestStep{
118+
{
119+
Config: testAccCloudStackIPAddress_networkProjectInheritance,
120+
Check: resource.ComposeTestCheckFunc(
121+
testAccCheckCloudStackIPAddressExists(
122+
"cloudstack_ipaddress.foo", &ipaddr),
123+
// Verify the project was inherited from the network
124+
resource.TestCheckResourceAttr(
125+
"cloudstack_ipaddress.foo", "project", "terraform"),
126+
testAccCheckCloudStackIPAddressProjectInherited(&ipaddr),
127+
),
128+
},
129+
},
130+
})
131+
}
132+
87133
func testAccCheckCloudStackIPAddressExists(
88134
n string, ipaddr *cloudstack.PublicIpAddress) resource.TestCheckFunc {
89135
return func(s *terraform.State) error {
@@ -113,6 +159,18 @@ func testAccCheckCloudStackIPAddressExists(
113159
}
114160
}
115161

162+
func testAccCheckCloudStackIPAddressProjectInherited(
163+
ipaddr *cloudstack.PublicIpAddress) resource.TestCheckFunc {
164+
return func(s *terraform.State) error {
165+
166+
if ipaddr.Project != "terraform" {
167+
return fmt.Errorf("Expected project to be 'terraform' (inherited from VPC or network), got: %s", ipaddr.Project)
168+
}
169+
170+
return nil
171+
}
172+
}
173+
116174
func testAccCheckCloudStackIPAddressDestroy(s *terraform.State) error {
117175
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
118176

@@ -186,3 +244,34 @@ resource "cloudstack_ipaddress" "foo" {
186244
network_id = cloudstack_network.foo.id
187245
zone = cloudstack_vpc.foo.zone
188246
}`
247+
248+
const testAccCloudStackIPAddress_vpcProjectInheritance = `
249+
resource "cloudstack_vpc" "foo" {
250+
name = "terraform-vpc"
251+
cidr = "10.0.0.0/8"
252+
vpc_offering = "Default VPC offering"
253+
project = "terraform"
254+
zone = "Sandbox-simulator"
255+
}
256+
257+
resource "cloudstack_ipaddress" "foo" {
258+
vpc_id = cloudstack_vpc.foo.id
259+
zone = cloudstack_vpc.foo.zone
260+
# Note: project is NOT specified here - it should be inherited from the VPC
261+
}`
262+
263+
const testAccCloudStackIPAddress_networkProjectInheritance = `
264+
resource "cloudstack_network" "foo" {
265+
name = "terraform-network"
266+
display_text = "terraform-network"
267+
cidr = "10.1.1.0/24"
268+
network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService"
269+
project = "terraform"
270+
source_nat_ip = true
271+
zone = "Sandbox-simulator"
272+
}
273+
274+
resource "cloudstack_ipaddress" "foo" {
275+
network_id = cloudstack_network.foo.id
276+
# Note: project is NOT specified here - it should be inherited from the network
277+
}`

website/docs/r/ipaddress.html.markdown

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,63 @@ Acquires and associates a public IP.
1212

1313
## Example Usage
1414

15+
### Basic IP Address for Network
16+
1517
```hcl
1618
resource "cloudstack_ipaddress" "default" {
1719
network_id = "6eb22f91-7454-4107-89f4-36afcdf33021"
1820
}
1921
```
2022

23+
### IP Address for VPC
24+
25+
```hcl
26+
resource "cloudstack_vpc" "foo" {
27+
name = "my-vpc"
28+
cidr = "10.0.0.0/16"
29+
vpc_offering = "Default VPC offering"
30+
zone = "zone-1"
31+
}
32+
33+
resource "cloudstack_ipaddress" "vpc_ip" {
34+
vpc_id = cloudstack_vpc.foo.id
35+
}
36+
```
37+
38+
### IP Address with Automatic Project Inheritance
39+
40+
```hcl
41+
# Create a VPC in a project
42+
resource "cloudstack_vpc" "project_vpc" {
43+
name = "project-vpc"
44+
cidr = "10.0.0.0/16"
45+
vpc_offering = "Default VPC offering"
46+
project = "my-project"
47+
zone = "zone-1"
48+
}
49+
50+
# IP address automatically inherits project from VPC
51+
resource "cloudstack_ipaddress" "vpc_ip" {
52+
vpc_id = cloudstack_vpc.project_vpc.id
53+
# project is automatically inherited from the VPC
54+
}
55+
56+
# Or with a network
57+
resource "cloudstack_network" "project_network" {
58+
name = "project-network"
59+
cidr = "10.1.1.0/24"
60+
network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService"
61+
project = "my-project"
62+
zone = "zone-1"
63+
}
64+
65+
# IP address automatically inherits project from network
66+
resource "cloudstack_ipaddress" "network_ip" {
67+
network_id = cloudstack_network.project_network.id
68+
# project is automatically inherited from the network
69+
}
70+
```
71+
2172
## Argument Reference
2273

2374
The following arguments are supported:
@@ -35,7 +86,10 @@ The following arguments are supported:
3586
acquired and associated. Changing this forces a new resource to be created.
3687

3788
* `project` - (Optional) The name or ID of the project to deploy this
38-
instance to. Changing this forces a new resource to be created.
89+
instance to. Changing this forces a new resource to be created. If not
90+
specified and `vpc_id` is provided, the project will be automatically
91+
inherited from the VPC. If not specified and `network_id` is provided,
92+
the project will be automatically inherited from the network.
3993

4094
*NOTE: `network_id` and/or `zone` should have a value when `is_portable` is `false`!*
4195
*NOTE: Either `network_id` or `vpc_id` should have a value when `is_portable` is `true`!*

0 commit comments

Comments
 (0)