Skip to content
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

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from

Conversation

AniJ98
Copy link

@AniJ98 AniJ98 commented Sep 26, 2024

📝 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:

  • Listing Reserved IPs
  • Getting a specific Reserved IP
  • Reserving a new IP
  • Deleting a Reserved IP

Test coverage:

  • Resource test - Covers testing the functionality of reserving and deleting a reserved IP Address
  • Datasource test - Covers testing the functionality of listing all reserved IP addresses and fetching a particular reserved IP Address.

✔️ How to Test

What are the steps to reproduce the issue or verify the changes?

  1. Ensure you have a valid Linode API token.
Set up your environment:


    export LINODE_TOKEN="your_token_here"


  2. To run only Reserved IP related tests:


    make int-test PKG_NAME="linode/networkreservedips"

To run a specific test:

  make int-test PKG_NAME="linode/networkreservedips" ARGS="-run TestAccDataSource_reservedIP"
  1. Verify the test output for any failures or unexpected behavior.

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.

@AniJ98 AniJ98 requested a review from a team as a code owner September 26, 2024 15:15
@AniJ98 AniJ98 requested review from zliang-akamai and yec-akamai and removed request for a team September 26, 2024 15:15
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
Copy link
Member

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

Copy link
Contributor

@yec-akamai yec-akamai left a 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:

Comment on lines 78 to 116
// 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])
}
Copy link
Contributor

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.

Copy link
Author

@AniJ98 AniJ98 Oct 15, 2024

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.

Comment on lines 28 to 55
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)
}
Copy link
Contributor

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?

Copy link
Author

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"`
Copy link
Contributor

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.

Copy link
Author

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

Comment on lines 41 to 48
"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,
},
Copy link
Contributor

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?

Copy link
Author

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.

Comment on lines 85 to 89
"reserved_ips": schema.ListAttribute{
Description: "A list of all reserved IPs.",
Computed: true,
ElementType: reservedIPObjectType,
},
Copy link
Contributor

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.

Copy link
Author

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
Copy link
Contributor

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.

Copy link
Author

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.

Comment on lines 33 to 34
t.Logf("Starting TestAccResource_reserveIP with resName: %s, instanceName: %s, region: %s", resName, instanceName, testRegion)

Copy link
Contributor

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")
Copy link
Contributor

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.

Copy link
Author

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")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
t.Log("Running Check function")

Copy link
Author

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

Comment on lines 13 to 17
{{ define "reserved_ip_data_list" }}

data "linode_reserved_ip" "test" {}

{{ end }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{{ define "reserved_ip_data_list" }}
data "linode_reserved_ip" "test" {}
{{ end }}

We usually don't define two script in one file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants