-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Terraform Support for Managing Reserved IP Addresses #1598
base: dev
Are you sure you want to change the base?
Conversation
…anch before next release
… tests from being run by unit test targets
go.mod
Outdated
@@ -26,7 +26,7 @@ require ( | |||
github.com/hashicorp/terraform-plugin-mux v0.16.0 | |||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 | |||
github.com/hashicorp/terraform-plugin-testing v1.10.0 | |||
github.com/linode/linodego v1.41.0 | |||
github.com/linode/linodego v1.41.1-0.20240925173015-b20be2e986e0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's wait for next linodego release
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your hard work on the IP reserve resource and data source. I left some suggestions to build this resource better:
// List all reserved IPs | ||
filter := "" | ||
ips, err := d.Meta.Client.ListReservedIPAddresses(ctx, &linodego.ListOptions{Filter: filter}) | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Unable to list Reserved IP Addresses", | ||
err.Error(), | ||
) | ||
return | ||
} | ||
|
||
reservedIPs := make([]ReservedIPObject, len(ips)) | ||
for i, ip := range ips { | ||
reservedIPs[i] = ReservedIPObject{ | ||
ID: types.StringValue(ip.Address), | ||
Address: types.StringValue(ip.Address), | ||
Region: types.StringValue(ip.Region), | ||
Gateway: types.StringValue(ip.Gateway), | ||
SubnetMask: types.StringValue(ip.SubnetMask), | ||
Prefix: types.Int64Value(int64(ip.Prefix)), | ||
Type: types.StringValue(string(ip.Type)), | ||
Public: types.BoolValue(ip.Public), | ||
RDNS: types.StringValue(ip.RDNS), | ||
LinodeID: types.Int64Value(int64(ip.LinodeID)), | ||
Reserved: types.BoolValue(ip.Reserved), | ||
} | ||
} | ||
|
||
reservedIPsValue, diags := types.ListValueFrom(ctx, reservedIPObjectType, reservedIPs) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
data.ReservedIPs = reservedIPsValue | ||
|
||
// If there are IPs, populate the first one's details for backwards compatibility | ||
if len(ips) > 0 { | ||
data.parseIP(&ips[0]) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we trying to get a list of reserved_ips for a customer? If so, you will need to create a new data source, i.e., network_reserved_ips
only for listing and filtering reserved ips. Terraform don't mix it in a single data source.
You can take a look at other list data source in our code base for reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! I will be creating a new datasource for the list functionality.
type DataSourceModel struct { | ||
ID types.String `tfsdk:"id"` | ||
Address types.String `tfsdk:"address"` | ||
Region types.String `tfsdk:"region"` | ||
Gateway types.String `tfsdk:"gateway"` | ||
SubnetMask types.String `tfsdk:"subnet_mask"` | ||
Prefix types.Int64 `tfsdk:"prefix"` | ||
Type types.String `tfsdk:"type"` | ||
Public types.Bool `tfsdk:"public"` | ||
RDNS types.String `tfsdk:"rdns"` | ||
LinodeID types.Int64 `tfsdk:"linode_id"` | ||
Reserved types.Bool `tfsdk:"reserved"` | ||
ReservedIPs types.List `tfsdk:"reserved_ips"` | ||
} | ||
|
||
func (data *DataSourceModel) parseIP(ip *linodego.InstanceIP) { | ||
data.ID = types.StringValue(ip.Address) | ||
data.Address = types.StringValue(ip.Address) | ||
data.Region = types.StringValue(ip.Region) | ||
data.Gateway = types.StringValue(ip.Gateway) | ||
data.SubnetMask = types.StringValue(ip.SubnetMask) | ||
data.Prefix = types.Int64Value(int64(ip.Prefix)) | ||
data.Type = types.StringValue(string(ip.Type)) | ||
data.Public = types.BoolValue(ip.Public) | ||
data.RDNS = types.StringValue(ip.RDNS) | ||
data.LinodeID = types.Int64Value(int64(ip.LinodeID)) | ||
data.Reserved = types.BoolValue(ip.Reserved) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move this data source model and parsing function to framwork_models
to keep the data source short and clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I will be doing it the next commit
RDNS types.String `tfsdk:"rdns"` | ||
LinodeID types.Int64 `tfsdk:"linode_id"` | ||
Reserved types.Bool `tfsdk:"reserved"` | ||
ReservedIPs types.List `tfsdk:"reserved_ips"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may need to build another data source for listing reserved IPs, instead of having it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I will be having a new datasource for this
"region": schema.StringAttribute{ | ||
Description: "The Region in which to reserve the IP address.", | ||
Optional: true, | ||
}, | ||
"address": schema.StringAttribute{ | ||
Description: "The reserved IP address.", | ||
Optional: true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I understand the endpoint correctly, but it looks like address is a required attribute to get this data source?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have made it optional since I am implementing both fetch and list endpoints in the same datasource. But now it seems like it is indeed a better idea to separate the functionalities into individual datasources. I will be doing that in the next commit.
"reserved_ips": schema.ListAttribute{ | ||
Description: "A list of all reserved IPs.", | ||
Computed: true, | ||
ElementType: reservedIPObjectType, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I mentioned above, we can remove this list to its own data source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah will be separating it into a new datasource
ip linodego.InstanceIP, | ||
preserveKnown bool, | ||
) diag.Diagnostics { | ||
var diags diag.Diagnostics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like no diags is raised from this function. You can just remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look into it. I will remove it if it is not being triggered.
t.Logf("Starting TestAccResource_reserveIP with resName: %s, instanceName: %s, region: %s", resName, instanceName, testRegion) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's ok not to log this info here.
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { | ||
t.Log("Running PreCheck") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May need to clean this up too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
Config: tmpl.ReserveIP(t, instanceName, testRegion), | ||
Check: resource.ComposeTestCheckFunc( | ||
func(s *terraform.State) error { | ||
t.Log("Running Check function") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t.Log("Running Check function") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove this line
{{ define "reserved_ip_data_list" }} | ||
|
||
data "linode_reserved_ip" "test" {} | ||
|
||
{{ end }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{{ define "reserved_ip_data_list" }} | |
data "linode_reserved_ip" "test" {} | |
{{ end }} |
We usually don't define two script in one file.
…responding test. Removed unnessary logs
📝 Description
This PR introduces comprehensive functionality and tests for Reserved IP Addresses in the terraform provider. The changes are necessary to provide robust support for managing Reserved IP addresses through terraform. The changes include:
Implementation of core Reserved IP operations:
Test coverage:
✔️ How to Test
What are the steps to reproduce the issue or verify the changes?
Ensure you have a valid Linode API token. Set up your environment:
export LINODE_TOKEN="your_token_here"
To run only Reserved IP related tests:
make int-test PKG_NAME="linode/networkreservedips"
To run a specific test:
Note:
Ensure you have proper permissions and sufficient quota in your Linode account to perform Reserved IP operations. Some tests may create and delete resources, so use a testing environment if possible. This test expects the account to have 0 prior reservations.