diff --git a/docs/data-sources/dhcp_dnsmasq.md b/docs/data-sources/dhcp_dnsmasq.md new file mode 100644 index 0000000..d1be9fb --- /dev/null +++ b/docs/data-sources/dhcp_dnsmasq.md @@ -0,0 +1,44 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "openwrt_dhcp_dnsmasq Data Source - openwrt" +subcategory: "" +description: |- + A lightweight DHCP and caching DNS server. +--- + +# openwrt_dhcp_dnsmasq (Data Source) + +A lightweight DHCP and caching DNS server. + +## Example Usage + +```terraform +data "openwrt_dhcp_dnsmasq" "testing" { + id = "testing" +} +``` + + +## Schema + +### Required + +- `id` (String) Name of the section. This name is only used when interacting with UCI directly. + +### Read-Only + +- `authoritative` (Boolean) Force dnsmasq into authoritative mode. This speeds up DHCP leasing. Used if this is the only server on the network. +- `domain` (String) DNS domain handed out to DHCP clients. +- `domainneeded` (Boolean) Never forward queries for plain names, without dots or domain parts, to upstream nameservers. +- `ednspacket_max` (Number) Specify the largest EDNS.0 UDP packet which is supported by the DNS forwarder. +- `expandhosts` (Boolean) Never forward queries for plain names, without dots or domain parts, to upstream nameservers. +- `leasefile` (String) Store DHCP leases in this file. +- `local` (String) Look up DNS entries for this domain from `/etc/hosts`. +- `localise_queries` (Boolean) Choose IP address to match the incoming interface if multiple addresses are assigned to a host name in `/etc/hosts`. +- `localservice` (Boolean) Accept DNS queries only from hosts whose address is on a local subnet. +- `readethers` (Boolean) Read static lease entries from `/etc/ethers`, re-read on SIGHUP. +- `rebind_localhost` (Boolean) Allows upstream 127.0.0.0/8 responses, required for DNS based blocklist services. Only takes effect if rebind protection is enabled. +- `rebind_protection` (Boolean) Enables DNS rebind attack protection by discarding upstream RFC1918 responses. +- `resolvfile` (String) Specifies an alternative resolv file. + + diff --git a/docs/resources/dhcp_dnsmasq.md b/docs/resources/dhcp_dnsmasq.md new file mode 100644 index 0000000..350264e --- /dev/null +++ b/docs/resources/dhcp_dnsmasq.md @@ -0,0 +1,73 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "openwrt_dhcp_dnsmasq Resource - openwrt" +subcategory: "" +description: |- + A lightweight DHCP and caching DNS server. +--- + +# openwrt_dhcp_dnsmasq (Resource) + +A lightweight DHCP and caching DNS server. + +## Example Usage + +```terraform +resource "openwrt_dhcp_dnsmasq" "this" { + domain = "testing" + expandhosts = true + id = "testing" + local = "/testing/" + rebind_localhost = true + rebind_protection = true +} +``` + + +## Schema + +### Required + +- `id` (String) Name of the section. This name is only used when interacting with UCI directly. + +### Optional + +- `authoritative` (Boolean) Force dnsmasq into authoritative mode. This speeds up DHCP leasing. Used if this is the only server on the network. +- `domain` (String) DNS domain handed out to DHCP clients. +- `domainneeded` (Boolean) Never forward queries for plain names, without dots or domain parts, to upstream nameservers. +- `ednspacket_max` (Number) Specify the largest EDNS.0 UDP packet which is supported by the DNS forwarder. +- `expandhosts` (Boolean) Never forward queries for plain names, without dots or domain parts, to upstream nameservers. +- `leasefile` (String) Store DHCP leases in this file. +- `local` (String) Look up DNS entries for this domain from `/etc/hosts`. +- `localise_queries` (Boolean) Choose IP address to match the incoming interface if multiple addresses are assigned to a host name in `/etc/hosts`. +- `localservice` (Boolean) Accept DNS queries only from hosts whose address is on a local subnet. +- `readethers` (Boolean) Read static lease entries from `/etc/ethers`, re-read on SIGHUP. +- `rebind_localhost` (Boolean) Allows upstream 127.0.0.0/8 responses, required for DNS based blocklist services. Only takes effect if rebind protection is enabled. +- `rebind_protection` (Boolean) Enables DNS rebind attack protection by discarding upstream RFC1918 responses. +- `resolvfile` (String) Specifies an alternative resolv file. + +## 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", "dnsmasq"]}' \ +# 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_dnsmasq.this cfg123456 +``` diff --git a/examples/data-sources/openwrt_dhcp_dnsmasq/data-source.tf b/examples/data-sources/openwrt_dhcp_dnsmasq/data-source.tf new file mode 100644 index 0000000..a6e0c20 --- /dev/null +++ b/examples/data-sources/openwrt_dhcp_dnsmasq/data-source.tf @@ -0,0 +1,3 @@ +data "openwrt_dhcp_dnsmasq" "testing" { + id = "testing" +} diff --git a/examples/resources/openwrt_dhcp_dnsmasq/import.sh b/examples/resources/openwrt_dhcp_dnsmasq/import.sh new file mode 100644 index 0000000..95aba2f --- /dev/null +++ b/examples/resources/openwrt_dhcp_dnsmasq/import.sh @@ -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", "dnsmasq"]}' \ +# 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_dnsmasq.this cfg123456 diff --git a/examples/resources/openwrt_dhcp_dnsmasq/resource.tf b/examples/resources/openwrt_dhcp_dnsmasq/resource.tf new file mode 100644 index 0000000..a8037ad --- /dev/null +++ b/examples/resources/openwrt_dhcp_dnsmasq/resource.tf @@ -0,0 +1,8 @@ +resource "openwrt_dhcp_dnsmasq" "this" { + domain = "testing" + expandhosts = true + id = "testing" + local = "/testing/" + rebind_localhost = true + rebind_protection = true +} diff --git a/openwrt/dhcp/dnsmasq/acceptance_test.go b/openwrt/dhcp/dnsmasq/acceptance_test.go new file mode 100644 index 0000000..e0b6bbe --- /dev/null +++ b/openwrt/dhcp/dnsmasq/acceptance_test.go @@ -0,0 +1,40 @@ +//go:build acceptance.test + +package dnsmasq_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() +} diff --git a/openwrt/dhcp/dnsmasq/dnsmasq.go b/openwrt/dhcp/dnsmasq/dnsmasq.go new file mode 100644 index 0000000..f4d0ef3 --- /dev/null +++ b/openwrt/dhcp/dnsmasq/dnsmasq.go @@ -0,0 +1,245 @@ +package dnsmasq + +import ( + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/joneshf/terraform-provider-openwrt/lucirpc" + "github.com/joneshf/terraform-provider-openwrt/openwrt/internal/lucirpcglue" +) + +const ( + authoritativeModeAttribute = "authoritative" + authoritativeModeAttributeDescription = "Force dnsmasq into authoritative mode. This speeds up DHCP leasing. Used if this is the only server on the network." + authoritativeModeUCIOption = "authoritative" + + domainAttribute = "domain" + domainAttributeDescription = "DNS domain handed out to DHCP clients." + domainUCIOption = "domain" + + domainNeededAttribute = "domainneeded" + domainNeededAttributeDescription = "Never forward queries for plain names, without dots or domain parts, to upstream nameservers." + domainNeededUCIOption = "domainneeded" + + ednsPacketMaxAttribute = "ednspacket_max" + ednsPacketMaxAttributeDescription = "Specify the largest EDNS.0 UDP packet which is supported by the DNS forwarder." + ednsPacketMaxUCIOption = "ednspacket_max" + + expandHostsAttribute = "expandhosts" + expandHostsAttributeDescription = "Never forward queries for plain names, without dots or domain parts, to upstream nameservers." + expandHostsUCIOption = "expandhosts" + + leaseFileAttribute = "leasefile" + leaseFileAttributeDescription = "Store DHCP leases in this file." + leaseFileUCIOption = "leasefile" + + localizeQueriesAttribute = "localise_queries" + localizeQueriesAttributeDescription = "Choose IP address to match the incoming interface if multiple addresses are assigned to a host name in `/etc/hosts`." + localizeQueriesUCIOption = "localise_queries" + + localLookupAttribute = "local" + localLookupAttributeDescription = "Look up DNS entries for this domain from `/etc/hosts`." + localLookupUCIOption = "local" + + localServiceAttribute = "localservice" + localServiceAttributeDescription = "Accept DNS queries only from hosts whose address is on a local subnet." + localServiceUCIOption = "localservice" + + readEthersAttribute = "readethers" + readEthersAttributeDescription = "Read static lease entries from `/etc/ethers`, re-read on SIGHUP." + readEthersUCIOption = "readethers" + + rebindLocalhostAttribute = "rebind_localhost" + rebindLocalhostAttributeDescription = "Allows upstream 127.0.0.0/8 responses, required for DNS based blocklist services. Only takes effect if rebind protection is enabled." + rebindLocalhostUCIOption = "rebind_localhost" + + rebindProtectionAttribute = "rebind_protection" + rebindProtectionAttributeDescription = "Enables DNS rebind attack protection by discarding upstream RFC1918 responses." + rebindProtectionUCIOption = "rebind_protection" + + resolvFileAttribute = "resolvfile" + resolvFileAttributeDescription = "Specifies an alternative resolv file." + resolvFileUCIOption = "resolvfile" + + schemaDescription = "A lightweight DHCP and caching DNS server." + + uciConfig = "dhcp" + uciType = "dnsmasq" +) + +var ( + authoritativeModeSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: authoritativeModeAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetAuthoritativeMode, authoritativeModeAttribute, authoritativeModeUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetAuthoritativeMode, authoritativeModeAttribute, authoritativeModeUCIOption), + } + + domainSchemaAttribute = lucirpcglue.StringSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: domainAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionString(modelSetDomain, domainAttribute, domainUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionString(modelGetDomain, domainAttribute, domainUCIOption), + } + + domainNeededSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: domainNeededAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetDomainNeeded, domainNeededAttribute, domainNeededUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetDomainNeeded, domainNeededAttribute, domainNeededUCIOption), + } + + ednsPacketMaxSchemaAttribute = lucirpcglue.Int64SchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: ednsPacketMaxAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionInt64(modelSetEDNSPacketMax, ednsPacketMaxAttribute, ednsPacketMaxUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionInt64(modelGetEDNSPacketMax, ednsPacketMaxAttribute, ednsPacketMaxUCIOption), + } + + expandHostsSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: expandHostsAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetExpandHosts, expandHostsAttribute, expandHostsUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetExpandHosts, expandHostsAttribute, expandHostsUCIOption), + } + + leaseFileSchemaAttribute = lucirpcglue.StringSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: leaseFileAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionString(modelSetLeaseFile, leaseFileAttribute, leaseFileUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionString(modelGetLeaseFile, leaseFileAttribute, leaseFileUCIOption), + } + + localizeQueriesSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: localizeQueriesAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetLocalizeQueries, localizeQueriesAttribute, localizeQueriesUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetLocalizeQueries, localizeQueriesAttribute, localizeQueriesUCIOption), + } + + localLookupSchemaAttribute = lucirpcglue.StringSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: localLookupAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionString(modelSetLocalLookup, localLookupAttribute, localLookupUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionString(modelGetLocalLookup, localLookupAttribute, localLookupUCIOption), + } + + localServiceSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: localServiceAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetLocalService, localServiceAttribute, localServiceUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetLocalService, localServiceAttribute, localServiceUCIOption), + } + + readEthersSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: readEthersAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetReadEthers, readEthersAttribute, readEthersUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetReadEthers, readEthersAttribute, readEthersUCIOption), + } + + rebindLocalhostSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: rebindLocalhostAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetRebindLocalhost, rebindLocalhostAttribute, rebindLocalhostUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetRebindLocalhost, rebindLocalhostAttribute, rebindLocalhostUCIOption), + } + + rebindProtectionSchemaAttribute = lucirpcglue.BoolSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: rebindProtectionAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionBool(modelSetRebindProtection, rebindProtectionAttribute, rebindProtectionUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionBool(modelGetRebindProtection, rebindProtectionAttribute, rebindProtectionUCIOption), + } + + resolvFileSchemaAttribute = lucirpcglue.StringSchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + Description: resolvFileAttributeDescription, + ReadResponse: lucirpcglue.ReadResponseOptionString(modelSetResolvFile, resolvFileAttribute, resolvFileUCIOption), + ResourceExistence: lucirpcglue.NoValidation, + UpsertRequest: lucirpcglue.UpsertRequestOptionString(modelGetResolvFile, resolvFileAttribute, resolvFileUCIOption), + } + + schemaAttributes = map[string]lucirpcglue.SchemaAttribute[model, lucirpc.Options, lucirpc.Options]{ + authoritativeModeAttribute: authoritativeModeSchemaAttribute, + domainAttribute: domainSchemaAttribute, + domainNeededAttribute: domainNeededSchemaAttribute, + ednsPacketMaxAttribute: ednsPacketMaxSchemaAttribute, + expandHostsAttribute: expandHostsSchemaAttribute, + leaseFileAttribute: leaseFileSchemaAttribute, + localizeQueriesAttribute: localizeQueriesSchemaAttribute, + localLookupAttribute: localLookupSchemaAttribute, + localServiceAttribute: localServiceSchemaAttribute, + lucirpcglue.IdAttribute: lucirpcglue.IdSchemaAttribute(modelGetId, modelSetId), + readEthersAttribute: readEthersSchemaAttribute, + rebindLocalhostAttribute: rebindLocalhostSchemaAttribute, + rebindProtectionAttribute: rebindProtectionSchemaAttribute, + resolvFileAttribute: resolvFileSchemaAttribute, + } +) + +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 { + AuthoritativeMode types.Bool `tfsdk:"authoritative"` + Domain types.String `tfsdk:"domain"` + DomainNeeded types.Bool `tfsdk:"domainneeded"` + EDNSPacketMax types.Int64 `tfsdk:"ednspacket_max"` + ExpandHosts types.Bool `tfsdk:"expandhosts"` + Id types.String `tfsdk:"id"` + LeaseFile types.String `tfsdk:"leasefile"` + LocalizeQueries types.Bool `tfsdk:"localise_queries"` + LocalLookup types.String `tfsdk:"local"` + LocalService types.Bool `tfsdk:"localservice"` + ReadEthers types.Bool `tfsdk:"readethers"` + RebindLocalhost types.Bool `tfsdk:"rebind_localhost"` + RebindProtection types.Bool `tfsdk:"rebind_protection"` + ResolvFile types.String `tfsdk:"resolvfile"` +} + +func modelGetAuthoritativeMode(m model) types.Bool { return m.AuthoritativeMode } +func modelGetDomain(m model) types.String { return m.Domain } +func modelGetDomainNeeded(m model) types.Bool { return m.DomainNeeded } +func modelGetEDNSPacketMax(m model) types.Int64 { return m.EDNSPacketMax } +func modelGetExpandHosts(m model) types.Bool { return m.ExpandHosts } +func modelGetId(m model) types.String { return m.Id } +func modelGetLeaseFile(m model) types.String { return m.LeaseFile } +func modelGetLocalizeQueries(m model) types.Bool { return m.LocalizeQueries } +func modelGetLocalLookup(m model) types.String { return m.LocalLookup } +func modelGetLocalService(m model) types.Bool { return m.LocalService } +func modelGetReadEthers(m model) types.Bool { return m.ReadEthers } +func modelGetRebindLocalhost(m model) types.Bool { return m.RebindLocalhost } +func modelGetRebindProtection(m model) types.Bool { return m.RebindProtection } +func modelGetResolvFile(m model) types.String { return m.ResolvFile } + +func modelSetAuthoritativeMode(m *model, value types.Bool) { m.AuthoritativeMode = value } +func modelSetDomain(m *model, value types.String) { m.Domain = value } +func modelSetDomainNeeded(m *model, value types.Bool) { m.DomainNeeded = value } +func modelSetEDNSPacketMax(m *model, value types.Int64) { m.EDNSPacketMax = value } +func modelSetExpandHosts(m *model, value types.Bool) { m.ExpandHosts = value } +func modelSetId(m *model, value types.String) { m.Id = value } +func modelSetLeaseFile(m *model, value types.String) { m.LeaseFile = value } +func modelSetLocalizeQueries(m *model, value types.Bool) { m.LocalizeQueries = value } +func modelSetLocalLookup(m *model, value types.String) { m.LocalLookup = value } +func modelSetLocalService(m *model, value types.Bool) { m.LocalService = value } +func modelSetReadEthers(m *model, value types.Bool) { m.ReadEthers = value } +func modelSetRebindLocalhost(m *model, value types.Bool) { m.RebindLocalhost = value } +func modelSetRebindProtection(m *model, value types.Bool) { m.RebindProtection = value } +func modelSetResolvFile(m *model, value types.String) { m.ResolvFile = value } diff --git a/openwrt/dhcp/dnsmasq/dnsmasq_acceptance_test.go b/openwrt/dhcp/dnsmasq/dnsmasq_acceptance_test.go new file mode 100644 index 0000000..090754e --- /dev/null +++ b/openwrt/dhcp/dnsmasq/dnsmasq_acceptance_test.go @@ -0,0 +1,122 @@ +//go:build acceptance.test + +package dnsmasq_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{ + "domain": lucirpc.String("testing"), + "rebind_protection": lucirpc.Boolean(true), + } + ok, err := client.CreateSection(ctx, "dhcp", "dnsmasq", "testing", options) + assert.NilError(t, err) + assert.Check(t, ok) + + readDataSource := resource.TestStep{ + Config: fmt.Sprintf(` +%s + +data "openwrt_dhcp_dnsmasq" "testing" { + id = "testing" +} +`, + providerBlock, + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.openwrt_dhcp_dnsmasq.testing", "id", "testing"), + resource.TestCheckResourceAttr("data.openwrt_dhcp_dnsmasq.testing", "domain", "testing"), + resource.TestCheckResourceAttr("data.openwrt_dhcp_dnsmasq.testing", "rebind_protection", "true"), + ), + } + + 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_dnsmasq" "testing" { + domain = "testing" + id = "testing" + rebind_protection = true +} +`, + providerBlock, + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "id", "testing"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "domain", "testing"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "rebind_protection", "true"), + ), + } + importValidation := resource.TestStep{ + ImportState: true, + ImportStateVerify: true, + ResourceName: "openwrt_dhcp_dnsmasq.testing", + } + updateAndReadResource := resource.TestStep{ + Config: fmt.Sprintf(` +%s + +resource "openwrt_dhcp_dnsmasq" "testing" { + domain = "testing" + expandhosts = true + id = "testing" + local = "/testing/" + rebind_localhost = true + rebind_protection = true +} +`, + providerBlock, + ), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "id", "testing"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "domain", "testing"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "expandhosts", "true"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "local", "/testing/"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "rebind_localhost", "true"), + resource.TestCheckResourceAttr("openwrt_dhcp_dnsmasq.testing", "rebind_protection", "true"), + ), + } + + acceptancetest.TerraformSteps( + t, + createAndReadResource, + importValidation, + updateAndReadResource, + ) +} diff --git a/openwrt/provider.go b/openwrt/provider.go index 50c5287..019e935 100644 --- a/openwrt/provider.go +++ b/openwrt/provider.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/joneshf/terraform-provider-openwrt/lucirpc" + "github.com/joneshf/terraform-provider-openwrt/openwrt/dhcp/dnsmasq" "github.com/joneshf/terraform-provider-openwrt/openwrt/internal/lucirpcglue" "github.com/joneshf/terraform-provider-openwrt/openwrt/network/device" "github.com/joneshf/terraform-provider-openwrt/openwrt/network/globals" @@ -158,6 +159,7 @@ func (p *openWrtProvider) DataSources( ) []func() datasource.DataSource { return []func() datasource.DataSource{ device.NewDataSource, + dnsmasq.NewDataSource, globals.NewDataSource, networkinterface.NewDataSource, networkswitch.NewDataSource, @@ -184,6 +186,7 @@ func (p *openWrtProvider) Resources( ) []func() resource.Resource { return []func() resource.Resource{ device.NewResource, + dnsmasq.NewResource, globals.NewResource, networkinterface.NewResource, networkswitch.NewResource,