Skip to content

Commit

Permalink
feat: add port_isolation resources (#33)
Browse files Browse the repository at this point in the history
Signed-off-by: Brenno Oliveira <[email protected]>
  • Loading branch information
brennoo authored Jan 13, 2025
1 parent 3e0f2d6 commit 438478c
Show file tree
Hide file tree
Showing 7 changed files with 458 additions and 0 deletions.
28 changes: 28 additions & 0 deletions docs/resources/port_isolation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
page_title: "hrui_port_isolation (Resource)"
description: |-
---

# hrui_port_isolation (Resource)



## Example Usage

```terraform
resource "hrui_port_isolation" "example" {
port = "Port 1"
isolation_list = ["Port 2", "Port 3"]
}
```

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

### Required

- `isolation_list` (List of String) List of isolated ports for the specified port.
- `port` (String) The port name for which isolation will be configured. Acts as an implicit identifier.


4 changes: 4 additions & 0 deletions examples/resources/hrui_port_isolation/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "hrui_port_isolation" "example" {
port = "Port 1"
isolation_list = ["Port 2", "Port 3"]
}
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/brennoo/terraform-provider-hrui/internal/resources/loop_protocol"
"github.com/brennoo/terraform-provider-hrui/internal/resources/mac_static"
"github.com/brennoo/terraform-provider-hrui/internal/resources/mac_table"
"github.com/brennoo/terraform-provider-hrui/internal/resources/port_isolation"
"github.com/brennoo/terraform-provider-hrui/internal/resources/port_mirroring"
"github.com/brennoo/terraform-provider-hrui/internal/resources/port_settings"
"github.com/brennoo/terraform-provider-hrui/internal/resources/port_statistics"
Expand Down Expand Up @@ -81,5 +82,6 @@ func (p *hruiProvider) Resources(ctx context.Context) []func() resource.Resource
igmp_snooping_static.NewResource,
trunk_group.NewResource,
port_mirroring.NewResource,
port_isolation.NewResource,
}
}
10 changes: 10 additions & 0 deletions internal/resources/port_isolation/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package port_isolation

import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

type portIsolationModel struct {
Port types.String `tfsdk:"port"`
IsolationList types.List `tfsdk:"isolation_list"`
}
208 changes: 208 additions & 0 deletions internal/resources/port_isolation/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package port_isolation

import (
"context"
"fmt"

"github.com/brennoo/terraform-provider-hrui/internal/sdk"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// portIsolationResource defines the resource implementation.
type portIsolationResource struct {
client *sdk.HRUIClient
}

// NewResource initializes and returns a new resource instance.
func NewResource() resource.Resource {
return &portIsolationResource{}
}

// Metadata defines the resource metadata.
func (r *portIsolationResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_port_isolation"
}

// Schema defines the schema for the resource.
func (r *portIsolationResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"port": schema.StringAttribute{
Required: true,
Description: "The port name for which isolation will be configured. Acts as an implicit identifier.",
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"isolation_list": schema.ListAttribute{
ElementType: types.StringType,
Required: true,
Description: "List of isolated ports for the specified port.",
},
},
}
}

// Configure assigns the provider-configured client to the resource.
func (r *portIsolationResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*sdk.HRUIClient)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Provider Data Type",
fmt.Sprintf("Expected *sdk.HRUIClient, got: %T", req.ProviderData),
)
return
}

r.client = client
}

// Read fetches the current port isolation and updates the state.
func (r *portIsolationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// Read the state into the model
var state portIsolationModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Fetch port isolation configuration from the SDK
portIsolations, err := r.client.GetPortIsolation()
if err != nil {
resp.Diagnostics.AddError(
"Error Reading Port Isolation",
fmt.Sprintf("Failed to fetch port isolation configurations: %s", err.Error()),
)
return
}

// Find the isolation configuration for the current port
port := state.Port.ValueString()
var isolationList []string
for _, isolation := range portIsolations {
if isolation.Port == port {
// Use isolation list from the backend as-is
isolationList = isolation.IsolationList
break
}
}

// Update the Terraform state
state.IsolationList = convertToTerraformList(isolationList)
diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
}

// Create sets up the port isolation using the given plan values.
func (r *portIsolationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
// Read the plan into the model
var plan portIsolationModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Call SDK to configure port isolation
port := plan.Port.ValueString()
isolationList := extractStrings(ctx, plan.IsolationList)

err := r.client.ConfigurePortIsolation(port, isolationList)
if err != nil {
resp.Diagnostics.AddError(
"Error Creating Port Isolation",
fmt.Sprintf("Failed to configure port isolation for port '%s': %s", port, err.Error()),
)
return
}

// Save the state
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

// Update modifies the port isolation.
func (r *portIsolationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// Read the plan into the model
var plan portIsolationModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Call SDK to update port isolation
port := plan.Port.ValueString()
isolationList := extractStrings(ctx, plan.IsolationList)

err := r.client.ConfigurePortIsolation(port, isolationList)
if err != nil {
resp.Diagnostics.AddError(
"Error Updating Port Isolation",
fmt.Sprintf("Failed to update port isolation for port '%s': %s", port, err.Error()),
)
return
}

// Save the updated state
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

// Delete removes the port isolation.
func (r *portIsolationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
// Read the state into the model
var state portIsolationModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Clear the port isolation
port := state.Port.ValueString()
err := r.client.DeletePortIsolation(port)
if err != nil {
resp.Diagnostics.AddError(
"Error Deleting Port Isolation",
fmt.Sprintf("Failed to delete port isolation for port '%s': %s", port, err.Error()),
)
return
}
}

// extractStrings extracts Go strings from a Terraform List attribute.
func extractStrings(ctx context.Context, list types.List) []string {
if list.IsUnknown() || list.IsNull() {
return nil
}

var result []string
list.ElementsAs(ctx, &result, false)
return result
}

// convertToTerraformList converts a list of strings into a Terraform List attribute.
func convertToTerraformList(data []string) types.List {
elements := make([]attr.Value, len(data))
for i, v := range data {
elements[i] = types.StringValue(v)
}

list, diags := types.ListValue(types.StringType, elements)
if diags.HasError() {
return types.ListNull(types.StringType)
}

return list
}
Loading

0 comments on commit 438478c

Please sign in to comment.