Skip to content

Commit

Permalink
Merge pull request #186 from alrayyes/feat/ip-reverse-lookup
Browse files Browse the repository at this point in the history
feat: implement publiccloud ip resource
  • Loading branch information
alrayyes authored Dec 6, 2024
2 parents 341606e + c5f3aa0 commit fbe588c
Show file tree
Hide file tree
Showing 10 changed files with 520 additions and 78 deletions.
2 changes: 2 additions & 0 deletions docs/resources/public_cloud_instance.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ Read-Only:

Read-Only:

- `instance_id` (String)
- `ip` (String)
- `reverse_lookup` (String)

## Import

Expand Down
43 changes: 43 additions & 0 deletions docs/resources/public_cloud_ip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "leaseweb_public_cloud_ip Resource - leaseweb"
subcategory: ""
description: |-
Note:
This resource cannot be created, only imported.Once imported, this resource cannot be deleted.
---

# leaseweb_public_cloud_ip (Resource)

**Note:**
- This resource cannot be created, only imported.
- Once imported, this resource cannot be deleted.

## Example Usage

```terraform
# Manage example Public Cloud ip
resource "leaseweb_public_cloud_ip" "example" {
instance_id = "695ddd91-051f-4dd6-9120-938a927a47d0"
ip = "10.0.0.1"
reverse_lookup = "example.com"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `instance_id` (String)
- `ip` (String)
- `reverse_lookup` (String)

## Import

Import is supported using the following syntax:

```shell
# Public Cloud ip can be imported by specifying <instance_id>,<ip>.
terraform import leaseweb_public_cloud_ip.example 695ddd91-051f-4dd6-9120-938a927a47d0,10.0.0.1
```
2 changes: 2 additions & 0 deletions examples/resources/leaseweb_public_cloud_ip/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Public Cloud ip can be imported by specifying <instance_id>,<ip>.
terraform import leaseweb_public_cloud_ip.example 695ddd91-051f-4dd6-9120-938a927a47d0,10.0.0.1
6 changes: 6 additions & 0 deletions examples/resources/leaseweb_public_cloud_ip/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Manage example Public Cloud ip
resource "leaseweb_public_cloud_ip" "example" {
instance_id = "695ddd91-051f-4dd6-9120-938a927a47d0"
ip = "10.0.0.1"
reverse_lookup = "example.com"
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,6 @@ func (p *leasewebProvider) Resources(_ context.Context) []func() resource.Resour
publiccloud.NewLoadBalancerResource,
publiccloud.NewLoadBalancerListenerResource,
publiccloud.NewTargetGroupResource,
publiccloud.NewIPResource,
}
}
66 changes: 66 additions & 0 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -2727,3 +2728,68 @@ func TestAccPublicCloudISOsDataSource(t *testing.T) {
})
})
}

func TestAccPublicCloudIpResource(t *testing.T) {
t.Run("imports and updates an ip", func(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// ImportState testing
{
Config: providerConfig + `
resource "leaseweb_public_cloud_ip" "test" {
instance_id = "695ddd91-051f-4dd6-9120-938a927a47d0"
ip = "10.0.0.1"
reverse_lookup = "a-valid-domain.xpto"
}
`,
ResourceName: "leaseweb_public_cloud_ip.test",
ImportState: true,
ImportStatePersist: true,
ImportStateId: "695ddd91-051f-4dd6-9120-938a927a47d0,10.0.0.1",
ImportStateVerifyIdentifierAttribute: "instance_id",
ImportStateCheck: func(states []*terraform.InstanceState) error {
for _, state := range states {
if state.Attributes["ip"] != "10.0.0.1" || state.Attributes["instance_id"] != "695ddd91-051f-4dd6-9120-938a927a47d0" {
return fmt.Errorf("%v", state.Attributes)
}
}

return nil
},
},
// Update and Read testing
{
Config: providerConfig + `
resource "leaseweb_public_cloud_ip" "test" {
instance_id = "695ddd91-051f-4dd6-9120-938a927a47d0"
ip = "10.0.0.1"
reverse_lookup = "a-valid-domain.xpto"
}
`,
},
},
// Delete testing automatically occurs in TestCase
})
})

t.Run("creating a new ip causes an error", func(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: providerConfig + `
resource "leaseweb_public_cloud_ip" "test" {
instance_id = "695ddd91-051f-4dd6-9120-938a927a47d0"
ip = "10.0.0.1"
reverse_lookup = "example.com"
}
`,
ExpectError: regexp.MustCompile(
"Resource public_cloud_ip can only be imported, not created.",
),
},
},
})
})
}
83 changes: 33 additions & 50 deletions internal/provider/publiccloud/instance_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ func (c contractResourceModel) AttributeTypes() map[string]attr.Type {
}
}

func adaptContractToContractResource(sdkContract publiccloud.Contract) contractResourceModel {
func adaptContractToContractResource(contract publiccloud.Contract) contractResourceModel {
return contractResourceModel{
BillingFrequency: basetypes.NewInt32Value(int32(sdkContract.GetBillingFrequency())),
Term: basetypes.NewInt32Value(int32(sdkContract.GetTerm())),
Type: basetypes.NewStringValue(string(sdkContract.GetType())),
EndsAt: utils.AdaptNullableTimeToStringValue(sdkContract.EndsAt.Get()),
State: basetypes.NewStringValue(string(sdkContract.GetState())),
BillingFrequency: basetypes.NewInt32Value(int32(contract.GetBillingFrequency())),
Term: basetypes.NewInt32Value(int32(contract.GetTerm())),
Type: basetypes.NewStringValue(string(contract.GetType())),
EndsAt: utils.AdaptNullableTimeToStringValue(contract.EndsAt.Get()),
State: basetypes.NewStringValue(string(contract.GetState())),
}
}

Expand Down Expand Up @@ -81,7 +81,7 @@ func (i instanceResourceModel) AttributeTypes() map[string]attr.Type {
"root_disk_storage_type": types.StringType,
"ips": types.ListType{
ElemType: types.ObjectType{
AttrTypes: iPResourceModel{}.AttributeTypes(),
AttrTypes: ipResourceModel{}.AttributeTypes(),
},
},
"contract": types.ObjectType{
Expand All @@ -95,7 +95,7 @@ func (i instanceResourceModel) GetLaunchInstanceOpts(ctx context.Context) (
*publiccloud.LaunchInstanceOpts,
error,
) {
sdkRootDiskStorageType, err := publiccloud.NewStorageTypeFromValue(
rootDiskStorageType, err := publiccloud.NewStorageTypeFromValue(
i.RootDiskStorageType.ValueString(),
)
if err != nil {
Expand All @@ -114,49 +114,49 @@ func (i instanceResourceModel) GetLaunchInstanceOpts(ctx context.Context) (
return nil, utils.ReturnError("GetLaunchInstanceOpts", contractDiags)
}

sdkContractType, err := publiccloud.NewContractTypeFromValue(
contractType, err := publiccloud.NewContractTypeFromValue(
contract.Type.ValueString(),
)
if err != nil {
return nil, err
}

sdkContractTerm, err := publiccloud.NewContractTermFromValue(
contractTerm, err := publiccloud.NewContractTermFromValue(
contract.Term.ValueInt32(),
)
if err != nil {
return nil, err
}

sdkBillingFrequency, err := publiccloud.NewBillingFrequencyFromValue(
billingFrequency, err := publiccloud.NewBillingFrequencyFromValue(
contract.BillingFrequency.ValueInt32(),
)
if err != nil {
return nil, err
}

sdkRegionName, err := publiccloud.NewRegionNameFromValue(
regionName, err := publiccloud.NewRegionNameFromValue(
i.Region.ValueString(),
)
if err != nil {
return nil, err
}

sdkTypeName, err := publiccloud.NewTypeNameFromValue(
typeName, err := publiccloud.NewTypeNameFromValue(
i.Type.ValueString(),
)
if err != nil {
return nil, err
}

opts := publiccloud.NewLaunchInstanceOpts(
*sdkRegionName,
*sdkTypeName,
*regionName,
*typeName,
image.ID.ValueString(),
*sdkContractType,
*sdkContractTerm,
*sdkBillingFrequency,
*sdkRootDiskStorageType,
*contractType,
*contractTerm,
*billingFrequency,
*rootDiskStorageType,
)

opts.MarketAppId = utils.AdaptStringPointerValueToNullableString(i.MarketAppID)
Expand Down Expand Up @@ -256,7 +256,7 @@ func adaptInstanceToInstanceResource(

ips, err := utils.AdaptSdkModelsToListValue(
sdkInstance.Ips,
iPResourceModel{}.AttributeTypes(),
ipResourceModel{}.AttributeTypes(),
ctx,
adaptIpToIPResource,
)
Expand Down Expand Up @@ -307,7 +307,7 @@ func adaptInstanceDetailsToInstanceResource(

ips, err := utils.AdaptSdkModelsToListValue(
sdkInstanceDetails.Ips,
iPResourceModel{}.AttributeTypes(),
ipResourceModel{}.AttributeTypes(),
ctx,
adaptIpDetailsToIPResource,
)
Expand All @@ -330,28 +330,6 @@ func adaptInstanceDetailsToInstanceResource(
return &instance, nil
}

type iPResourceModel struct {
IP types.String `tfsdk:"ip"`
}

func (i iPResourceModel) AttributeTypes() map[string]attr.Type {
return map[string]attr.Type{
"ip": types.StringType,
}
}

func adaptIpToIPResource(sdkIp publiccloud.Ip) iPResourceModel {
return iPResourceModel{
IP: basetypes.NewStringValue(sdkIp.GetIp()),
}
}

func adaptIpDetailsToIPResource(sdkIpDetails publiccloud.IpDetails) iPResourceModel {
return iPResourceModel{
IP: basetypes.NewStringValue(sdkIpDetails.GetIp()),
}
}

func NewInstanceResource() resource.Resource {
return &instanceResource{
name: "public_cloud_instance",
Expand Down Expand Up @@ -408,16 +386,15 @@ func (i *instanceResource) Create(
return
}

sdkInstance, httpResponse, err := i.client.LaunchInstance(ctx).
instance, httpResponse, err := i.client.LaunchInstance(ctx).
LaunchInstanceOpts(*opts).
Execute()

if err != nil {
utils.Error(ctx, &resp.Diagnostics, summary, err, httpResponse)
return
}

state, err := adaptInstanceToInstanceResource(*sdkInstance, ctx)
state, err := adaptInstanceToInstanceResource(*instance, ctx)
if err != nil {
resp.Diagnostics.AddError(summary, utils.DefaultErrMsg)
return
Expand Down Expand Up @@ -485,7 +462,7 @@ func (i *instanceResource) Read(
state.ID.ValueString(),
)

sdkInstance, httpResponse, err := i.client.
instance, httpResponse, err := i.client.
GetInstance(ctx, state.ID.ValueString()).
Execute()
if err != nil {
Expand All @@ -494,7 +471,7 @@ func (i *instanceResource) Read(
}

newState, err := adaptInstanceDetailsToInstanceResource(
*sdkInstance,
*instance,
ctx,
)
if err != nil {
Expand Down Expand Up @@ -529,15 +506,15 @@ func (i *instanceResource) Update(
return
}

sdkInstanceDetails, httpResponse, err := i.client.
instanceDetails, httpResponse, err := i.client.
UpdateInstance(ctx, plan.ID.ValueString()).
UpdateInstanceOpts(*opts).
Execute()
if err != nil {
utils.Error(ctx, &resp.Diagnostics, summary, err, httpResponse)
return
}
state, err := adaptInstanceDetailsToInstanceResource(*sdkInstanceDetails, ctx)
state, err := adaptInstanceDetailsToInstanceResource(*instanceDetails, ctx)
if err != nil {
utils.Error(ctx, &resp.Diagnostics, summary, err, nil)
return
Expand Down Expand Up @@ -671,6 +648,12 @@ func (i *instanceResource) Schema(
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"ip": schema.StringAttribute{Computed: true},
"instance_id": schema.StringAttribute{
Computed: true,
},
"reverse_lookup": schema.StringAttribute{
Computed: true,
},
},
},
},
Expand Down
Loading

0 comments on commit fbe588c

Please sign in to comment.