From 60ff5eca1b4c1df6b3b24480edbb7c7f3fe74384 Mon Sep 17 00:00:00 2001 From: Paul Tyng Date: Sun, 28 Mar 2021 14:20:23 -0400 Subject: [PATCH] Add unifi_dynamic_dns resource Fixes #126 --- docs/resources/dynamic_dns.md | 47 +++++ .../resources/unifi_dynamic_dns/resource.tf | 9 + go.mod | 2 +- go.sum | 4 +- internal/provider/lazy_client.go | 35 ++++ internal/provider/provider.go | 7 + internal/provider/resource_dynamic_dns.go | 186 ++++++++++++++++++ .../provider/resource_dynamic_dns_test.go | 36 ++++ 8 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 docs/resources/dynamic_dns.md create mode 100644 examples/resources/unifi_dynamic_dns/resource.tf create mode 100644 internal/provider/resource_dynamic_dns.go create mode 100644 internal/provider/resource_dynamic_dns_test.go diff --git a/docs/resources/dynamic_dns.md b/docs/resources/dynamic_dns.md new file mode 100644 index 0000000..3a6ce71 --- /dev/null +++ b/docs/resources/dynamic_dns.md @@ -0,0 +1,47 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "unifi_dynamic_dns Resource - terraform-provider-unifi" +subcategory: "" +description: |- + unifi_dynamic_dns manages dynamic DNS settings for different providers. +--- + +# unifi_dynamic_dns (Resource) + +`unifi_dynamic_dns` manages dynamic DNS settings for different providers. + +## Example Usage + +```terraform +resource "unifi_dynamic_dns" "test" { + service = "dyndns" + + host_name = "my-network.example.com" + + server = "domains.google.com" + login = var.dns_login + password = var.dns_password +} +``` + + +## Schema + +### Required + +- **host_name** (String) The host name to update in the dynamic DNS service. +- **service** (String) The Dynamic DNS service provider, various values are supported (for example `dyndns`, etc.). + +### Optional + +- **interface** (String) The interface for the dynamic DNS. Can be `wan` or `wan2`. Defaults to `wan`. +- **login** (String) The server for the dynamic DNS service. +- **password** (String, Sensitive) The server for the dynamic DNS service. +- **server** (String) The server for the dynamic DNS service. +- **site** (String) The name of the site to associate the dynamic DNS with. + +### Read-Only + +- **id** (String) The ID of the dynamic DNS. + + diff --git a/examples/resources/unifi_dynamic_dns/resource.tf b/examples/resources/unifi_dynamic_dns/resource.tf new file mode 100644 index 0000000..64ad1f7 --- /dev/null +++ b/examples/resources/unifi_dynamic_dns/resource.tf @@ -0,0 +1,9 @@ +resource "unifi_dynamic_dns" "test" { + service = "dyndns" + + host_name = "my-network.example.com" + + server = "domains.google.com" + login = var.dns_login + password = var.dns_password +} diff --git a/go.mod b/go.mod index 0e86de8..e0077d6 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/oklog/run v1.1.0 // indirect - github.com/paultyng/go-unifi v1.14.0 + github.com/paultyng/go-unifi v1.15.0 github.com/posener/complete v1.2.1 // indirect golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect diff --git a/go.sum b/go.sum index 3fc1b8d..a7d0f78 100644 --- a/go.sum +++ b/go.sum @@ -303,8 +303,8 @@ github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/paultyng/go-unifi v1.14.0 h1:xBtZnD+2fq+A+oSUz4NnpFRS4Wy6TW3NMcv+sg7MfvY= -github.com/paultyng/go-unifi v1.14.0/go.mod h1:aF1ya3pylyb7RRCcFxaOB6oZSWYlAnmD8ycv4AMW2+I= +github.com/paultyng/go-unifi v1.15.0 h1:XI1/xigMlG/KW9cElzHirF/QHZ+zPl1qSOOpGEldltc= +github.com/paultyng/go-unifi v1.15.0/go.mod h1:aF1ya3pylyb7RRCcFxaOB6oZSWYlAnmD8ycv4AMW2+I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/internal/provider/lazy_client.go b/internal/provider/lazy_client.go index 68dce3e..87331b9 100644 --- a/internal/provider/lazy_client.go +++ b/internal/provider/lazy_client.go @@ -459,3 +459,38 @@ func (c *lazyClient) UpdateRouting(ctx context.Context, site string, d *unifi.Ro } return c.inner.UpdateRouting(ctx, site, d) } + +func (c *lazyClient) ListDynamicDNS(ctx context.Context, site string) ([]unifi.DynamicDNS, error) { + if err := c.init(ctx); err != nil { + return nil, err + } + return c.inner.ListDynamicDNS(ctx, site) +} + +func (c *lazyClient) GetDynamicDNS(ctx context.Context, site, id string) (*unifi.DynamicDNS, error) { + if err := c.init(ctx); err != nil { + return nil, err + } + return c.inner.GetDynamicDNS(ctx, site, id) +} + +func (c *lazyClient) DeleteDynamicDNS(ctx context.Context, site, id string) error { + if err := c.init(ctx); err != nil { + return err + } + return c.inner.DeleteDynamicDNS(ctx, site, id) +} + +func (c *lazyClient) CreateDynamicDNS(ctx context.Context, site string, d *unifi.DynamicDNS) (*unifi.DynamicDNS, error) { + if err := c.init(ctx); err != nil { + return nil, err + } + return c.inner.CreateDynamicDNS(ctx, site, d) +} + +func (c *lazyClient) UpdateDynamicDNS(ctx context.Context, site string, d *unifi.DynamicDNS) (*unifi.DynamicDNS, error) { + if err := c.init(ctx); err != nil { + return nil, err + } + return c.inner.UpdateDynamicDNS(ctx, site, d) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index ac33133..12e7fd2 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -83,6 +83,7 @@ func New(version string) func() *schema.Provider { ResourcesMap: map[string]*schema.Resource{ // TODO: "unifi_ap_group" "unifi_device": resourceDevice(), + "unifi_dynamic_dns": resourceDynamicDNS(), "unifi_firewall_group": resourceFirewallGroup(), "unifi_firewall_rule": resourceFirewallRule(), "unifi_network": resourceNetwork(), @@ -201,6 +202,12 @@ type unifiClient interface { DeleteRouting(ctx context.Context, site, id string) error CreateRouting(ctx context.Context, site string, d *unifi.Routing) (*unifi.Routing, error) UpdateRouting(ctx context.Context, site string, d *unifi.Routing) (*unifi.Routing, error) + + ListDynamicDNS(ctx context.Context, site string) ([]unifi.DynamicDNS, error) + GetDynamicDNS(ctx context.Context, site, id string) (*unifi.DynamicDNS, error) + DeleteDynamicDNS(ctx context.Context, site, id string) error + CreateDynamicDNS(ctx context.Context, site string, d *unifi.DynamicDNS) (*unifi.DynamicDNS, error) + UpdateDynamicDNS(ctx context.Context, site string, d *unifi.DynamicDNS) (*unifi.DynamicDNS, error) } type client struct { diff --git a/internal/provider/resource_dynamic_dns.go b/internal/provider/resource_dynamic_dns.go new file mode 100644 index 0000000..bf7137a --- /dev/null +++ b/internal/provider/resource_dynamic_dns.go @@ -0,0 +1,186 @@ +package provider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/paultyng/go-unifi/unifi" +) + +func resourceDynamicDNS() *schema.Resource { + return &schema.Resource{ + Description: "`unifi_dynamic_dns` manages dynamic DNS settings for different providers.", + + Create: resourceDynamicDNSCreate, + Read: resourceDynamicDNSRead, + Update: resourceDynamicDNSUpdate, + Delete: resourceDynamicDNSDelete, + Importer: &schema.ResourceImporter{ + State: importSiteAndID, + }, + + Schema: map[string]*schema.Schema{ + "id": { + Description: "The ID of the dynamic DNS.", + Type: schema.TypeString, + Computed: true, + }, + "site": { + Description: "The name of the site to associate the dynamic DNS with.", + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "interface": { + Description: "The interface for the dynamic DNS. Can be `wan` or `wan2`.", + Type: schema.TypeString, + Optional: true, + Default: "wan", + ForceNew: true, + }, + "service": { + Description: "The Dynamic DNS service provider, various values are supported (for example `dyndns`, etc.).", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "host_name": { + Description: "The host name to update in the dynamic DNS service.", + Type: schema.TypeString, + Required: true, + }, + "server": { + Description: "The server for the dynamic DNS service.", + Type: schema.TypeString, + Optional: true, + }, + "login": { + Description: "The server for the dynamic DNS service.", + Type: schema.TypeString, + Optional: true, + }, + "password": { + Description: "The server for the dynamic DNS service.", + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + + //TODO: options support? + }, + } +} + +func resourceDynamicDNSCreate(d *schema.ResourceData, meta interface{}) error { + c := meta.(*client) + + req, err := resourceDynamicDNSGetResourceData(d) + if err != nil { + return err + } + + site := d.Get("site").(string) + if site == "" { + site = c.site + } + + resp, err := c.c.CreateDynamicDNS(context.TODO(), site, req) + if err != nil { + return err + } + + d.SetId(resp.ID) + + return resourceDynamicDNSSetResourceData(resp, d, site) +} + +func resourceDynamicDNSGetResourceData(d *schema.ResourceData) (*unifi.DynamicDNS, error) { + r := &unifi.DynamicDNS{ + Interface: d.Get("interface").(string), + Service: d.Get("service").(string), + + HostName: d.Get("host_name").(string), + + Server: d.Get("server").(string), + Login: d.Get("login").(string), + XPassword: d.Get("password").(string), + } + + return r, nil +} + +func resourceDynamicDNSSetResourceData(resp *unifi.DynamicDNS, d *schema.ResourceData, site string) error { + d.Set("interface", resp.Interface) + d.Set("service", resp.Service) + + d.Set("host_name", resp.HostName) + + d.Set("server", resp.Server) + d.Set("login", resp.Login) + d.Set("password", resp.XPassword) + + return nil +} + +func resourceDynamicDNSRead(d *schema.ResourceData, meta interface{}) error { + c := meta.(*client) + + id := d.Id() + + site := d.Get("site").(string) + if site == "" { + site = c.site + } + + resp, err := c.c.GetDynamicDNS(context.TODO(), site, id) + if _, ok := err.(*unifi.NotFoundError); ok { + d.SetId("") + return nil + } + if err != nil { + return err + } + + return resourceDynamicDNSSetResourceData(resp, d, site) +} + +func resourceDynamicDNSUpdate(d *schema.ResourceData, meta interface{}) error { + c := meta.(*client) + + req, err := resourceDynamicDNSGetResourceData(d) + if err != nil { + return err + } + + req.ID = d.Id() + + site := d.Get("site").(string) + if site == "" { + site = c.site + } + req.SiteID = site + + resp, err := c.c.UpdateDynamicDNS(context.TODO(), site, req) + if err != nil { + return err + } + + return resourceDynamicDNSSetResourceData(resp, d, site) +} + +func resourceDynamicDNSDelete(d *schema.ResourceData, meta interface{}) error { + c := meta.(*client) + + id := d.Id() + + site := d.Get("site").(string) + if site == "" { + site = c.site + } + err := c.c.DeleteDynamicDNS(context.TODO(), site, id) + if _, ok := err.(*unifi.NotFoundError); ok { + return nil + } + return err +} diff --git a/internal/provider/resource_dynamic_dns_test.go b/internal/provider/resource_dynamic_dns_test.go new file mode 100644 index 0000000..d638bee --- /dev/null +++ b/internal/provider/resource_dynamic_dns_test.go @@ -0,0 +1,36 @@ +package provider + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDynamicDNS_dyndns(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { preCheck(t) }, + ProviderFactories: providerFactories, + // TODO: CheckDestroy: , + Steps: []resource.TestStep{ + { + Config: testAccDynamicDNSConfig, + // Check: resource.ComposeTestCheckFunc( + // // testCheckFirewallGroupExists(t, "name"), + // ), + }, + importStep("unifi_dynamic_dns.test"), + }, + }) +} + +const testAccDynamicDNSConfig = ` +resource "unifi_dynamic_dns" "test" { + service = "dyndns" + + host_name = "test.example.com" + + server = "dyndns.example.com" + login = "testuser" + password = "password" +} +`