Skip to content

Commit

Permalink
Add support for dhcp.domain
Browse files Browse the repository at this point in the history
Last resource for the `dhcp` config. This is a bit redundant with the
`dhcp.host` stuff. But, it has a purpose. There are times when you need
to rebind a host name to an IP address (like when you want to provide a
subdomain). And this is where the `dhcp.domain` is useful.

It's unclear if there is more to this resource. There doesn't seem to be
any documentation on the OpenWrt wiki. There's only two fields in the
LuCI UI, so it seems like the whole thing has been implemented. If not,
we can always add it later.

Branch: joneshf/add-support-for-dhcp-domain
Pull-Request: #132
  • Loading branch information
joneshf authored Apr 9, 2023
1 parent 654cd1e commit 552dbb4
Show file tree
Hide file tree
Showing 9 changed files with 367 additions and 0 deletions.
33 changes: 33 additions & 0 deletions docs/data-sources/dhcp_domain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "openwrt_dhcp_domain Data Source - openwrt"
subcategory: ""
description: |-
Binds a domain name to an IP address.
---

# openwrt_dhcp_domain (Data Source)

Binds a domain name to an IP address.

## Example Usage

```terraform
data "openwrt_dhcp_domain" "testing" {
id = "testing"
}
```

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

### Required

- `id` (String) Name of the section. This name is only used when interacting with UCI directly.

### Read-Only

- `ip` (String) The IP address to be used for this domain.
- `name` (String) Hostname to assign.


56 changes: 56 additions & 0 deletions docs/resources/dhcp_domain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "openwrt_dhcp_domain Resource - openwrt"
subcategory: ""
description: |-
Binds a domain name to an IP address.
---

# openwrt_dhcp_domain (Resource)

Binds a domain name to an IP address.

## Example Usage

```terraform
resource "openwrt_dhcp_domain" "testing" {
id = "testing"
ip = "192.168.1.50"
name = "testing"
}
```

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

### Required

- `id` (String) Name of the section. This name is only used when interacting with UCI directly.
- `ip` (String) The IP address to be used for this domain.
- `name` (String) Hostname to assign.

## Import

Import is supported using the following syntax:

```shell
# Find the Terraform id from LuCI's JSON-RPC API.
# One way to find this information is with `curl` and `jq`:
#
# curl \
# --data '{"id": 0, "method": "foreach", "params": ["dhcp", "domain"]}' \
# http://192.168.1.1/cgi-bin/luci/rpc/uci?auth=$AUTH_TOKEN \
# | jq '.result | map({terraformId: .[".name"]})'
#
# This command will output something like:
#
# [
# {
# "terraformId": "cfg123456",
# }
# ]
#
# We'd then use the information to import the appropriate resource:

terraform import openwrt_dhcp_domain.this cfg123456
```
3 changes: 3 additions & 0 deletions examples/data-sources/openwrt_dhcp_domain/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "openwrt_dhcp_domain" "testing" {
id = "testing"
}
19 changes: 19 additions & 0 deletions examples/resources/openwrt_dhcp_domain/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Find the Terraform id from LuCI's JSON-RPC API.
# One way to find this information is with `curl` and `jq`:
#
# curl \
# --data '{"id": 0, "method": "foreach", "params": ["dhcp", "domain"]}' \
# http://192.168.1.1/cgi-bin/luci/rpc/uci?auth=$AUTH_TOKEN \
# | jq '.result | map({terraformId: .[".name"]})'
#
# This command will output something like:
#
# [
# {
# "terraformId": "cfg123456",
# }
# ]
#
# We'd then use the information to import the appropriate resource:

terraform import openwrt_dhcp_domain.this cfg123456
5 changes: 5 additions & 0 deletions examples/resources/openwrt_dhcp_domain/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resource "openwrt_dhcp_domain" "testing" {
id = "testing"
ip = "192.168.1.50"
name = "testing"
}
40 changes: 40 additions & 0 deletions openwrt/dhcp/domain/acceptance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build acceptance.test

package domain_test

import (
"context"
"fmt"
"log"
"os"
"testing"

"github.com/joneshf/terraform-provider-openwrt/internal/acceptancetest"
"github.com/ory/dockertest/v3"
)

var (
dockerPool *dockertest.Pool
)

func TestMain(m *testing.M) {
var (
code int
err error
tearDown func()
)
ctx := context.Background()
tearDown, dockerPool, err = acceptancetest.Setup(ctx)
defer func() {
tearDown()
os.Exit(code)
}()
if err != nil {
fmt.Printf("Problem setting up tests: %s", err)
code = 1
return
}

log.Printf("Running tests")
code = m.Run()
}
92 changes: 92 additions & 0 deletions openwrt/dhcp/domain/domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package domain

import (
"regexp"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/joneshf/terraform-provider-openwrt/lucirpc"
"github.com/joneshf/terraform-provider-openwrt/openwrt/internal/lucirpcglue"
)

const (
hostnameAttribute = "name"
hostnameAttributeDescription = "Hostname to assign."
hostnameUCIOption = "name"

ipAddressAttribute = "ip"
ipAddressAttributeDescription = "The IP address to be used for this domain."
ipAddressUCIOption = "ip"

schemaDescription = "Binds a domain name to an IP address."

uciConfig = "dhcp"
uciType = "domain"
)

var (
hostnameSchemaAttribute = lucirpcglue.StringSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{
Description: hostnameAttributeDescription,
ReadResponse: lucirpcglue.ReadResponseOptionString(modelSetHostname, hostnameAttribute, hostnameUCIOption),
ResourceExistence: lucirpcglue.Required,
UpsertRequest: lucirpcglue.UpsertRequestOptionString(modelGetHostname, hostnameAttribute, hostnameUCIOption),
}

ipAddressSchemaAttribute = lucirpcglue.StringSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{
Description: ipAddressAttributeDescription,
ReadResponse: lucirpcglue.ReadResponseOptionString(modelSetIPAddress, ipAddressAttribute, ipAddressUCIOption),
ResourceExistence: lucirpcglue.Required,
UpsertRequest: lucirpcglue.UpsertRequestOptionString(modelGetIPAddress, ipAddressAttribute, ipAddressUCIOption),
Validators: []validator.String{
stringvalidator.Any(
stringvalidator.RegexMatches(
regexp.MustCompile("^([[:digit:]]{1,3}.){3}[[:digit:]]{1,3}$"),
`must be a valid IP address (e.g. "192.168.3.1")`,
),
),
},
}

schemaAttributes = map[string]lucirpcglue.SchemaAttribute[model, lucirpc.Options, lucirpc.Options]{
hostnameAttribute: hostnameSchemaAttribute,
ipAddressAttribute: ipAddressSchemaAttribute,
lucirpcglue.IdAttribute: lucirpcglue.IdSchemaAttribute(modelGetId, modelSetId),
}
)

func NewDataSource() datasource.DataSource {
return lucirpcglue.NewDataSource(
modelGetId,
schemaAttributes,
schemaDescription,
uciConfig,
uciType,
)
}

func NewResource() resource.Resource {
return lucirpcglue.NewResource(
modelGetId,
schemaAttributes,
schemaDescription,
uciConfig,
uciType,
)
}

type model struct {
Hostname types.String `tfsdk:"name"`
Id types.String `tfsdk:"id"`
IPAddress types.String `tfsdk:"ip"`
}

func modelGetHostname(m model) types.String { return m.Hostname }
func modelGetId(m model) types.String { return m.Id }
func modelGetIPAddress(m model) types.String { return m.IPAddress }

func modelSetHostname(m *model, value types.String) { m.Hostname = value }
func modelSetId(m *model, value types.String) { m.Id = value }
func modelSetIPAddress(m *model, value types.String) { m.IPAddress = value }
116 changes: 116 additions & 0 deletions openwrt/dhcp/domain/domain_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//go:build acceptance.test

package domain_test

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/joneshf/terraform-provider-openwrt/internal/acceptancetest"
"github.com/joneshf/terraform-provider-openwrt/lucirpc"
"gotest.tools/v3/assert"
)

func TestDataSourceAcceptance(t *testing.T) {
ctx := context.Background()
openWrtServer := acceptancetest.RunOpenWrtServer(
ctx,
*dockerPool,
t,
)
client := openWrtServer.LuCIRPCClient(
ctx,
t,
)
providerBlock := openWrtServer.ProviderBlock()
options := lucirpc.Options{
"ip": lucirpc.String("192.168.1.50"),
"name": lucirpc.String("testing"),
}
ok, err := client.CreateSection(ctx, "dhcp", "domain", "testing", options)
assert.NilError(t, err)
assert.Check(t, ok)

readDataSource := resource.TestStep{
Config: fmt.Sprintf(`
%s
data "openwrt_dhcp_domain" "testing" {
id = "testing"
}
`,
providerBlock,
),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.openwrt_dhcp_domain.testing", "id", "testing"),
resource.TestCheckResourceAttr("data.openwrt_dhcp_domain.testing", "ip", "192.168.1.50"),
resource.TestCheckResourceAttr("data.openwrt_dhcp_domain.testing", "name", "testing"),
),
}

acceptancetest.TerraformSteps(
t,
readDataSource,
)
}

func TestResourceAcceptance(t *testing.T) {
ctx := context.Background()
openWrtServer := acceptancetest.RunOpenWrtServer(
ctx,
*dockerPool,
t,
)
providerBlock := openWrtServer.ProviderBlock()

createAndReadResource := resource.TestStep{
Config: fmt.Sprintf(`
%s
resource "openwrt_dhcp_domain" "testing" {
id = "testing"
ip = "192.168.1.50"
name = "testing"
}
`,
providerBlock,
),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("openwrt_dhcp_domain.testing", "id", "testing"),
resource.TestCheckResourceAttr("openwrt_dhcp_domain.testing", "ip", "192.168.1.50"),
resource.TestCheckResourceAttr("openwrt_dhcp_domain.testing", "name", "testing"),
),
}
importValidation := resource.TestStep{
ImportState: true,
ImportStateVerify: true,
ResourceName: "openwrt_dhcp_domain.testing",
}
updateAndReadResource := resource.TestStep{
Config: fmt.Sprintf(`
%s
resource "openwrt_dhcp_domain" "testing" {
id = "testing"
ip = "192.168.1.51"
name = "testing-1"
}
`,
providerBlock,
),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("openwrt_dhcp_domain.testing", "id", "testing"),
resource.TestCheckResourceAttr("openwrt_dhcp_domain.testing", "ip", "192.168.1.51"),
resource.TestCheckResourceAttr("openwrt_dhcp_domain.testing", "name", "testing-1"),
),
}

acceptancetest.TerraformSteps(
t,
createAndReadResource,
importValidation,
updateAndReadResource,
)
}
3 changes: 3 additions & 0 deletions openwrt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/joneshf/terraform-provider-openwrt/lucirpc"
"github.com/joneshf/terraform-provider-openwrt/openwrt/dhcp/dhcp"
"github.com/joneshf/terraform-provider-openwrt/openwrt/dhcp/dnsmasq"
"github.com/joneshf/terraform-provider-openwrt/openwrt/dhcp/domain"
"github.com/joneshf/terraform-provider-openwrt/openwrt/dhcp/host"
"github.com/joneshf/terraform-provider-openwrt/openwrt/dhcp/odhcpd"
"github.com/joneshf/terraform-provider-openwrt/openwrt/internal/lucirpcglue"
Expand Down Expand Up @@ -164,6 +165,7 @@ func (p *openWrtProvider) DataSources(
device.NewDataSource,
dhcp.NewDataSource,
dnsmasq.NewDataSource,
domain.NewDataSource,
globals.NewDataSource,
host.NewDataSource,
networkinterface.NewDataSource,
Expand Down Expand Up @@ -194,6 +196,7 @@ func (p *openWrtProvider) Resources(
device.NewResource,
dhcp.NewResource,
dnsmasq.NewResource,
domain.NewResource,
globals.NewResource,
host.NewResource,
networkinterface.NewResource,
Expand Down

0 comments on commit 552dbb4

Please sign in to comment.