synergiator opened a new issue, #291:
URL: https://github.com/apache/cloudstack-terraform-provider/issues/291
## Problem
(an existing problem, analysis by Opus 4.6R )
The `cloudstack_ipaddress` resource always lets CloudStack auto-select the
next free IP. There is no way to request a particular address.
This blocks a common enterprise pattern: an operator dedicates an intranet
VLAN/IP range to an account (via `cloudstack_vlan_ip_range` with `account` +
`domain_id`), then the tenant must acquire a *specific* IP from that range
into a VPC — for example because firewall rules, DNS records, or routing
tables on the corporate side are pre-provisioned for that exact address.
The CloudStack API (`associateIpAddress`) already accepts an optional
`ipaddress` parameter, and the Go SDK (`cloudstack-go/v2`) already exposes
`AssociateIpAddressParams.SetIpaddress(string)`. The Terraform provider
simply never calls it.
## Analysis
| Layer | Status |
|-------|--------|
| CloudStack API (`associateIpAddress`) | `ipaddress` parameter supported |
| Go SDK `v2.18.1` (`AssociateIpAddressParams`) | `SetIpaddress(string)`
exists |
| Terraform provider `cloudstack_ipaddress` | `ip_address` is
**Computed-only** — never sent to the API |
The fix is small and self-contained:
1. Change the `ip_address` schema field from `Computed`-only to
`Optional + Computed + ForceNew`.
2. In the Create function, if the user supplied `ip_address`, call
`p.SetIpaddress(...)` before the API call.
3. No changes to Read/Delete — `ip_address` is already read back from the
API response.
## What happens if not implemented
- Users who need a deterministic IP in a VPC (intranet routing,
pre-provisioned
firewall/DNS) must fall back to a `local-exec` provisioner or an external
script calling `cmk` / raw HTTP after `terraform apply`.
- The IP is created outside Terraform state, so it cannot be referenced by
other resources, is invisible to `terraform plan`, and will not be
destroyed
on `terraform destroy`.
- Drift detection is impossible: Terraform shows a Computed `ip_address` that
may differ from the one the post-script allocated.
## Files to touch
```
cloudstack/resource_cloudstack_ipaddress.go (schema + create function)
cloudstack/resource_cloudstack_ipaddress_test.go (acceptance test for
specific IP)
website/docs/r/ipaddress.html.markdown (document the new field)
```
## Code diffs
### `cloudstack/resource_cloudstack_ipaddress.go`
#### 1. Schema — make `ip_address` optional + force-new
```diff
"ip_address": {
- Type: schema.TypeString,
- Computed: true,
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ForceNew: true,
},
```
Full context (lines 70-73):
```go
// BEFORE
"ip_address": {
Type: schema.TypeString,
Computed: true,
},
// AFTER
"ip_address": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
```
#### 2. Create function — pass the requested IP to the API
Insert after the `p.SetVpcid` block (line 110) and before the `zone` block
(line 112):
```diff
if vpcid, ok := d.GetOk("vpc_id"); ok {
// Set the vpcid
p.SetVpcid(vpcid.(string))
}
+ if ipaddress, ok := d.GetOk("ip_address"); ok {
+ p.SetIpaddress(ipaddress.(string))
+ }
+
if zone, ok := d.GetOk("zone"); ok {
```
Full context (lines 107-121):
```go
// BEFORE
if vpcid, ok := d.GetOk("vpc_id"); ok {
// Set the vpcid
p.SetVpcid(vpcid.(string))
}
if zone, ok := d.GetOk("zone"); ok {
// AFTER
if vpcid, ok := d.GetOk("vpc_id"); ok {
// Set the vpcid
p.SetVpcid(vpcid.(string))
}
if ipaddress, ok := d.GetOk("ip_address"); ok {
p.SetIpaddress(ipaddress.(string))
}
if zone, ok := d.GetOk("zone"); ok {
```
No changes needed in `resourceCloudStackIPAddressRead` — line 168 already
reads back the allocated address:
```go
d.Set("ip_address", ip.Ipaddress)
```
No changes needed in `resourceCloudStackIPAddressDelete`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]