Skip to content

Commit 415eab5

Browse files
chore: remove address_type and make cidr_range optional.
1 parent dbc9e38 commit 415eab5

File tree

9 files changed

+74
-125
lines changed

9 files changed

+74
-125
lines changed

docs/resources/ip.md

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,43 @@
22
page_title: "random_ip Resource - terraform-provider-random"
33
subcategory: ""
44
description: |-
5-
The resource random_ip generates a random IP address from a given CIDR range based on the address type specified.
5+
The random_ip resource generates a random IP address, either IPv4 or IPv6. By default, it randomly chooses between 0.0.0.0/0 (IPv4) and ::/0 (IPv6). You can influence the IP type by specifying a cidr_range.
66
---
77

88
# random_ip (Resource)
99

10-
The resource `random_ip` generates a random IP address from a given CIDR range based on the address type specified.
10+
The `random_ip` resource generates a random IP address, either IPv4 or IPv6. By default, it randomly chooses between 0.0.0.0/0 (IPv4) and ::/0 (IPv6). You can influence the IP type by specifying a `cidr_range`.
1111

1212
## Example Usage
1313

14-
### ipv4
14+
```terraform
15+
resource "random_ip" "example" {}
16+
```
17+
18+
### IPv4
1519

1620
```terraform
1721
resource "ip" "example" {
18-
address_type = "ipv4"
19-
cidr_range = "10.1.0.0/16"
22+
cidr_range = "10.1.0.0/16"
2023
}
2124
```
2225

2326
### IPv6
2427

2528
```terraform
2629
resource "ip" "example" {
27-
address_type = "ipv4"
28-
cidr_range = "10.1.0.0/16"
30+
cidr_range = "10.1.0.0/16"
2931
}
3032
```
3133

3234
### Using a count
3335

34-
It could be useful to randomly generate a number of addresses. This can be done using a count.
36+
It could be useful to randomly generate a number of IP addresses. This can be done using a [count](https://developer.hashicorp.com/terraform/language/meta-arguments/count).
3537

3638
```terraform
3739
resource "random_ip" "example" {
38-
count = 20
39-
address_type = "ipv4"
40-
cidr_range = "192.168.1.0/28"
40+
count = 20
41+
cidr_range = "192.168.1.0/28"
4142
}
4243
4344
output "random_ipv4_addresses" {
@@ -47,14 +48,13 @@ output "random_ipv4_addresses" {
4748

4849
### Using a count followed by a distinct
4950

50-
Keep in mind that using a count you could end up with duplicate addresses.
51-
If you want to avoid this, perform a [distinct](https://developer.hashicorp.com/terraform/language/functions/distinct) on the list of addresses.
51+
Keep in mind that using a [count](https://developer.hashicorp.com/terraform/language/meta-arguments/count) you could end up with duplicate IP addresses.
52+
If you want to avoid this, perform a [distinct](https://developer.hashicorp.com/terraform/language/functions/distinct) on the list of IP addresses.
5253

5354
```terraform
5455
resource "random_ip" "example" {
55-
count = 50
56-
address_type = "ipv4"
57-
cidr_range = "192.168.1.0/28"
56+
count = 50
57+
cidr_range = "192.168.1.0/28"
5858
}
5959
6060
output "random_distinct_ipv4_addresses" {
@@ -65,13 +65,9 @@ output "random_distinct_ipv4_addresses" {
6565
<!-- schema generated by tfplugindocs -->
6666
## Schema
6767

68-
### Required
69-
70-
- `address_type` (String) A string indicating the type of IP address to generate. Valid values are `ipv4` and `ipv6`.
71-
- `cidr_range` (String) A CIDR range from which to allocate the IP address.
72-
7368
### Optional
7469

70+
- `cidr_range` (String) A CIDR range from which to allocate the IP address.
7571
- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
7672

7773
### Read-Only

examples/resources/random_ip/basic.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
resource "random_ip" "example" {}

examples/resources/random_ip/count.tf

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
resource "random_ip" "example" {
2-
count = 20
3-
address_type = "ipv4"
4-
cidr_range = "192.168.1.0/28"
2+
count = 20
3+
cidr_range = "192.168.1.0/28"
54
}
65

76
output "random_ipv4_addresses" {

examples/resources/random_ip/count_distinct.tf

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
resource "random_ip" "example" {
2-
count = 50
3-
address_type = "ipv4"
4-
cidr_range = "192.168.1.0/28"
2+
count = 50
3+
cidr_range = "192.168.1.0/28"
54
}
65

76
output "random_distinct_ipv4_addresses" {

examples/resources/random_ip/ipv4.tf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
resource "ip" "example" {
2-
address_type = "ipv4"
3-
cidr_range = "10.1.0.0/16"
2+
cidr_range = "10.1.0.0/16"
43
}

examples/resources/random_ip/ipv6.tf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
resource "ip" "example" {
2-
address_type = "ipv6"
3-
cidr_range = "2001:db8::/32"
2+
cidr_range = "2001:db8::/32"
43
}

internal/provider/random_ip.go

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ import (
88
"fmt"
99
"math/rand"
1010
"net"
11+
"time"
1112

12-
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
1313
"github.com/hashicorp/terraform-plugin-framework/resource"
1414
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
1515
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1616
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
17-
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
1817
"github.com/hashicorp/terraform-plugin-framework/types"
1918

2019
"github.com/terraform-providers/terraform-provider-random/internal/diagnostics"
@@ -37,8 +36,7 @@ func (r *ipResource) Metadata(_ context.Context, req resource.MetadataRequest, r
3736

3837
func (r *ipResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
3938
resp.Schema = schema.Schema{
40-
Description: "The resource `random_ip` generates a random IP address from a given CIDR range based on the " +
41-
"address type specified.",
39+
Description: "The `random_ip` resource generates a random IP address, either IPv4 or IPv6. By default, it randomly chooses between 0.0.0.0/0 (IPv4) and ::/0 (IPv6). You can influence the IP type by specifying a `cidr_range`.",
4240
Attributes: map[string]schema.Attribute{
4341
"keepers": schema.MapAttribute{
4442
Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
@@ -49,19 +47,10 @@ func (r *ipResource) Schema(ctx context.Context, req resource.SchemaRequest, res
4947
mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
5048
},
5149
},
52-
"address_type": schema.StringAttribute{
53-
Description: "A string indicating the type of IP address to generate. Valid values are `ipv4` and `ipv6`.",
54-
Required: true,
55-
PlanModifiers: []planmodifier.String{
56-
stringplanmodifier.RequiresReplace(),
57-
},
58-
Validators: []validator.String{
59-
stringvalidator.OneOf([]string{"ipv4", "ipv6"}...),
60-
},
61-
},
6250
"cidr_range": schema.StringAttribute{
6351
Description: "A CIDR range from which to allocate the IP address.",
64-
Required: true,
52+
Computed: true,
53+
Optional: true,
6554
PlanModifiers: []planmodifier.String{
6655
stringplanmodifier.RequiresReplace(),
6756
},
@@ -93,11 +82,19 @@ func (r *ipResource) Create(ctx context.Context, req resource.CreateRequest, res
9382
return
9483
}
9584

96-
addressType := plan.AddressType.ValueString()
9785
cidrRange := plan.CIDRRange.ValueString()
86+
// Check if CIDR range is empty, and if so, set it to either 0.0.0.0/0 or ::/0
87+
if cidrRange == "" {
88+
r := rand.New(rand.NewSource(time.Now().UnixNano()))
89+
if r.Intn(2) == 0 {
90+
cidrRange = "0.0.0.0/0"
91+
} else {
92+
cidrRange = "::/0"
93+
}
94+
}
9895

9996
// Generate a random IP address from a given CIDR range.
100-
ip, err := getRandomIP(cidrRange, addressType)
97+
ip, err := getRandomIP(cidrRange)
10198
if err != nil {
10299
resp.Diagnostics.AddError(
103100
"Create Random IP error",
@@ -109,11 +106,10 @@ func (r *ipResource) Create(ctx context.Context, req resource.CreateRequest, res
109106
}
110107

111108
u := &ipModelV0{
112-
ID: types.StringValue("-"),
113-
Keepers: plan.Keepers,
114-
AddressType: types.StringValue(addressType),
115-
CIDRRange: types.StringValue(cidrRange),
116-
Result: types.StringValue(ip.String()),
109+
ID: types.StringValue("-"),
110+
Keepers: plan.Keepers,
111+
CIDRRange: types.StringValue(cidrRange),
112+
Result: types.StringValue(ip.String()),
117113
}
118114

119115
diags = resp.State.Set(ctx, u)
@@ -146,50 +142,39 @@ func (r *ipResource) Delete(ctx context.Context, req resource.DeleteRequest, res
146142
}
147143

148144
type ipModelV0 struct {
149-
ID types.String `tfsdk:"id"`
150-
Keepers types.Map `tfsdk:"keepers"`
151-
AddressType types.String `tfsdk:"address_type"`
152-
CIDRRange types.String `tfsdk:"cidr_range"`
153-
Result types.String `tfsdk:"result"`
145+
ID types.String `tfsdk:"id"`
146+
Keepers types.Map `tfsdk:"keepers"`
147+
CIDRRange types.String `tfsdk:"cidr_range"`
148+
Result types.String `tfsdk:"result"`
154149
}
155150

156-
func getRandomIP(cidrRange, addressType string) (net.IP, error) {
157-
// We first parse the CIDR range to check for errors
151+
func getRandomIP(cidrRange string) (net.IP, error) {
152+
// Parse the CIDR range to check for errors
158153
// and to get the network address and netmask.
159154
_, network, err := net.ParseCIDR(cidrRange)
160155
if err != nil {
161156
return nil, fmt.Errorf("error parsing CIDR range: %w", err)
162157
}
163158

164-
// Check if the length of the netmask is valid (either IPv4 or IPv6 length).
159+
// Get the netmask and determine the IP type (IPv4 or IPv6)
165160
netmaskBytes := network.Mask
161+
addressBytes := network.IP
162+
163+
// Check if the length of the netmask is valid (either IPv4 or IPv6 length).
166164
if len(netmaskBytes) != net.IPv4len && len(netmaskBytes) != net.IPv6len {
167165
return nil, fmt.Errorf("invalid netmask: must be either IPv4 or IPv6")
168166
}
169167

170-
// Get the network address as a byte slice, either in 4-byte (IPv4) or 16-byte (IPv6) form.
171-
var addressBytes net.IP
172-
switch addressType {
173-
case "ipv4":
174-
addressBytes = network.IP.To4() // Convert the IP to 4-byte form.
175-
case "ipv6":
176-
addressBytes = network.IP.To16() // Convert the IP to 16-byte form.
177-
default:
178-
return nil, fmt.Errorf("invalid address type: %s", addressType)
179-
}
180-
181168
// This typically occurs when the CIDR range is not of the same type as the address type.
182169
if len(netmaskBytes) != len(addressBytes) {
183170
return nil, fmt.Errorf("netmask byte length does not match IP address byte length")
184171
}
185172

186-
var picked []byte
173+
// Generate the random IP within the CIDR range.
174+
picked := make([]byte, len(addressBytes))
187175
for i := 0; i < len(netmaskBytes); i++ {
188-
// Combine the random bits, determined by the XOR of 255 with the netmask byte
189-
// and a randomly generated byte, with the original bits in the network address.
190-
// The bitwise OR operation ensures that bits are set where the netmask has 0s,
191-
// introducing randomness, while retaining the original bits where the netmask has 1s.
192-
picked = append(picked, ((255^netmaskBytes[i])&byte(rand.Intn(256)))|addressBytes[i])
176+
// Combine the random bits with the original network address
177+
picked[i] = ((255 ^ netmaskBytes[i]) & byte(rand.Intn(256))) | addressBytes[i]
193178
}
194179

195180
// Turn the randomized byte slice into an IP address.

0 commit comments

Comments
 (0)