Skip to content

Commit

Permalink
Implement resource_firewall_ipset_cidr
Browse files Browse the repository at this point in the history
  • Loading branch information
c10l committed Dec 26, 2022
1 parent 9937fa7 commit caccdd2
Show file tree
Hide file tree
Showing 10 changed files with 360 additions and 6 deletions.
4 changes: 2 additions & 2 deletions docs/resources/firewall_ipset.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ resource "proxmoxve_firewall_ipset" "management" {
comment = "this is an optional comment"
}
resource "proxmoxve_firewall_ipset" "infra_workstations" {
resource "proxmoxve_firewall_ipset_cidr" "infra_workstations" {
ipset_name = proxmoxve_firewall_ipset.management.name
cidr = "192.168.10.0/24"
comment = "this is the CIDR of the admin workstations network"
}
resource "proxmoxve_firewall_ipset" "infra_cicd" {
resource "proxmoxve_firewall_ipset_cidr" "infra_cicd" {
ipset_name = proxmoxve_firewall_ipset.management.name
cidr = "10.100.0.0/24"
comment = "this is the CIDR of the CI/CD server that runs Terraform and infra-as-code to manage the PVE cluster"
Expand Down
47 changes: 47 additions & 0 deletions docs/resources/firewall_ipset_cidr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "proxmoxve_firewall_ipset_cidr Resource - terraform-provider-proxmoxve"
subcategory: ""
description: |-
---

# proxmoxve_firewall_ipset_cidr (Resource)



## Example Usage

```terraform
resource "proxmoxve_firewall_ipset_cidr" "example" {
ipset_name = "ipset_name"
cidr = "10.0.1.0/24"
comment = "some_comment"
}
resource "proxmoxve_firewall_ipset_cidr" "negated" {
ipset_name = "ipset_name"
cidr = "2a01::/16"
no_match = true
comment = "block the Internet!"
}
```

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

### Required

- `cidr` (String) CIDR to be configured. e.g. `10.0.0.0/8`, `fd65::/16`.
- `ipset_name` (String) Name of the IPSet on which to attach this CIDR.

### Optional

- `comment` (String)
- `no_match` (Boolean) Set to `true` to negate the CIDR rather than matching it.

### Read-Only

- `id` (String) The ID of this resource.


12 changes: 12 additions & 0 deletions examples/resources/proxmoxve_firewall_ipset_cidr/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "proxmoxve_firewall_ipset_cidr" "example" {
ipset_name = "ipset_name"
cidr = "10.0.1.0/24"
comment = "some_comment"
}

resource "proxmoxve_firewall_ipset_cidr" "negated" {
ipset_name = "ipset_name"
cidr = "2a01::/16"
no_match = true
comment = "block the Internet!"
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ go 1.19
// replace github.com/c10l/proxmoxve-client-go => ../proxmoxve-client-go

require (
github.com/c10l/proxmoxve-client-go v0.0.0-20221226001506-b0fc39d1d49f
github.com/c10l/proxmoxve-client-go v0.0.0-20221226015439-53c7016c3ed6
github.com/hashicorp/terraform-plugin-docs v0.13.0
github.com/hashicorp/terraform-plugin-framework v1.0.1
github.com/hashicorp/terraform-plugin-go v0.14.2
github.com/hashicorp/terraform-plugin-log v0.7.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
github.com/stretchr/testify v1.7.2
)

require (
Expand Down Expand Up @@ -55,6 +56,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/pquerna/otp v1.4.0 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
Expand All @@ -72,4 +74,5 @@ require (
google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/c10l/proxmoxve-client-go v0.0.0-20221226001506-b0fc39d1d49f h1:xY5106PL2ZtVAl4joetMxAewergcb/1a40UnqaF8C2Y=
github.com/c10l/proxmoxve-client-go v0.0.0-20221226001506-b0fc39d1d49f/go.mod h1:ZApKlMtmPbGYDlLr3kbFvH9SWFArJELF6iZ50OuQMrk=
github.com/c10l/proxmoxve-client-go v0.0.0-20221226015439-53c7016c3ed6 h1:77Gy8yBomWkqHsxgCpWDLZnXMpZADVyQ/zq7AJ8vBhY=
github.com/c10l/proxmoxve-client-go v0.0.0-20221226015439-53c7016c3ed6/go.mod h1:ZApKlMtmPbGYDlLr3kbFvH9SWFArJELF6iZ50OuQMrk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func (p *ProxmoxVEProvider) Resources(ctx context.Context) []func() resource.Res
NewACMEPluginResource,
NewFirewallAliasResource,
NewFirewallIPSetResource,
NewFirewallIPSetCIDRResource,
}
}

Expand Down
200 changes: 200 additions & 0 deletions internal/provider/resource_firewall_ipset_cidr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package provider

import (
"context"
"fmt"
"strings"

proxmox "github.com/c10l/proxmoxve-client-go/api"
"github.com/c10l/proxmoxve-client-go/api/cluster/firewall/ipset/ipset_cidr"
"github.com/c10l/proxmoxve-client-go/helpers"
pvetypes "github.com/c10l/proxmoxve-client-go/helpers/types"
"github.com/hashicorp/terraform-plugin-framework/path"
"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"
)

// Ensure provider defined types fully satisfy framework interfaces
var _ resource.Resource = &FirewallIPSetCIDRResource{}
var _ resource.ResourceWithImportState = &FirewallIPSetCIDRResource{}

func NewFirewallIPSetCIDRResource() resource.Resource {
return &FirewallIPSetCIDRResource{}
}

// FirewallIPSetCIDRResource defines the resource implementation.
type FirewallIPSetCIDRResource struct {
client *proxmox.Client
}

// FirewallIPSetCIDRResource describes the resource data model.
type FirewallIPSetCIDRResourceModel struct {
ID types.String `tfsdk:"id"`
IPSetName types.String `tfsdk:"ipset_name"`
CIDR types.String `tfsdk:"cidr"`
NoMatch types.Bool `tfsdk:"no_match"`
Comment types.String `tfsdk:"comment"`
}

func (r *FirewallIPSetCIDRResource) typeName() string { return "firewall_ipset_cidr" }

func (r *FirewallIPSetCIDRResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_" + r.typeName()
}

func (r *FirewallIPSetCIDRResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"ipset_name": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
MarkdownDescription: "Name of the IPSet on which to attach this CIDR.",
},
"cidr": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
MarkdownDescription: "CIDR to be configured. e.g. `10.0.0.0/8`, `fd65::/16`.",
},
"no_match": schema.BoolAttribute{
Optional: true,
MarkdownDescription: "Set to `true` to negate the CIDR rather than matching it.",
},
"comment": schema.StringAttribute{
Optional: true,
},
},
}
}

func (r *FirewallIPSetCIDRResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

clientFunc, ok := req.ProviderData.(map[string]getClientFunc)["token"]

if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *proxmox.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

client, err := clientFunc()
if err != nil {
resp.Diagnostics.AddError(
"Unable to instantiate client",
err.Error(),
)
}

r.client = client
}

func (r *FirewallIPSetCIDRResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *FirewallIPSetCIDRResourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

postReq := ipset_cidr.PostRequest{Client: r.client, IPSetName: data.IPSetName.ValueString(), CIDR: data.CIDR.ValueString()}
if !data.NoMatch.IsNull() {
noMatch := pvetypes.PVEBool(data.NoMatch.ValueBool())
postReq.NoMatch = &noMatch
}
if !data.Comment.IsNull() {
postReq.Comment = helpers.PtrTo(data.Comment.ValueString())
}
err := postReq.Post()
if err != nil {
resp.Diagnostics.AddError("Error creating "+r.typeName(), err.Error())
return
}

id := fmt.Sprintf("%s/%s", data.IPSetName.ValueString(), data.CIDR.ValueString())
data.ID = types.StringValue(id)
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
}

func (r *FirewallIPSetCIDRResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *FirewallIPSetCIDRResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

ipSetCIDR, err := ipset_cidr.ItemGetRequest{Client: r.client, IPSetName: data.IPSetName.ValueString(), CIDR: data.CIDR.ValueString()}.Get()
if err != nil {
resp.Diagnostics.AddError(fmt.Sprintf("Error reading %s %s", r.typeName(), data.ID.ValueString()), err.Error())
return
}

data.CIDR = types.StringValue(ipSetCIDR.CIDR)
data.Comment = types.StringValue(*ipSetCIDR.Comment)
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
}

func (r *FirewallIPSetCIDRResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var state *FirewallIPSetCIDRResourceModel
var config *FirewallIPSetCIDRResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}

comment := config.Comment.ValueString()
noMatch := pvetypes.PVEBool(config.NoMatch.ValueBool())
itemPutReq := ipset_cidr.ItemPutRequest{
Client: r.client,
IPSetName: config.IPSetName.ValueString(),
CIDR: config.CIDR.ValueString(),
Comment: &comment,
NoMatch: &noMatch,
}
err := itemPutReq.Put()
if err != nil {
resp.Diagnostics.AddError("Error updating "+r.typeName(), err.Error())
return
}

state.Comment = types.StringValue(comment)
state.NoMatch = types.BoolValue(bool(noMatch))
resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
}

func (r *FirewallIPSetCIDRResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data *FirewallIPSetCIDRResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

err := ipset_cidr.ItemDeleteRequest{Client: r.client, IPSetName: data.IPSetName.ValueString(), CIDR: data.CIDR.ValueString()}.Delete()
if err != nil {
resp.Diagnostics.AddError("Error deleting "+r.typeName(), err.Error())
return
}
}

func (r *FirewallIPSetCIDRResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
ipSetName, cidr := r.splitID(req.ID)
resp.State.SetAttribute(ctx, path.Root("ipset_name"), ipSetName)
resp.State.SetAttribute(ctx, path.Root("cidr"), cidr)
}

func (r *FirewallIPSetCIDRResource) splitID(id string) (string, string) {
nameAndCIDR := strings.SplitN(id, "/", 2)
return nameAndCIDR[0], nameAndCIDR[1]
}
Loading

0 comments on commit caccdd2

Please sign in to comment.