Skip to content

Commit

Permalink
Merge pull request #2126 from suhrit-cf/master
Browse files Browse the repository at this point in the history
Add new resource for managed networks
  • Loading branch information
jacobbednarz authored Jan 10, 2023
2 parents b47d69e + b41cb56 commit f456811
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/2126.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
cloudflare_device_managed_networks
```
53 changes: 53 additions & 0 deletions docs/resources/device_managed_networks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
page_title: "cloudflare_device_managed_networks Resource - Cloudflare"
subcategory: ""
description: |-
Provides a Cloudflare Device Managed Network resource. Device managed networks allow for building location-aware device settings policies.
---

# cloudflare_device_managed_networks (Resource)

Provides a Cloudflare Device Managed Network resource. Device managed networks allow for building location-aware device settings policies.

## Example Usage

```terraform
resource "cloudflare_device_managed_networks" "managed_networks" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "managed-network-1"
type = "tls"
config {
tls_sockaddr = "foobar:1234"
sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
}
}
```
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `account_id` (String) The account identifier to target for the resource.
- `config` (Block List, Min: 1, Max: 1) The configuration containing information for the WARP client to detect the managed network. (see [below for nested schema](#nestedblock--config))
- `name` (String) The name of the Device Managed Network. Must be unique.
- `type` (String) The type of Device Managed Network. Available values: `tls`.

### Read-Only

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

<a id="nestedblock--config"></a>
### Nested Schema for `config`

Required:

- `sha256` (String) The SHA-256 hash of the TLS certificate presented by the host found at tls_sockaddr. If absent, regular certificate verification (trusted roots, valid timestamp, etc) will be used to validate the certificate.
- `tls_sockaddr` (String) A network address of the form "host:port" that the WARP client will use to detect the presence of a TLS host.

## Import

Import is supported using the following syntax:

```shell
$ terraform import cloudflare_device_managed_networks.example <account_id>/<device_managed_networks_id>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$ terraform import cloudflare_device_managed_networks.example <account_id>/<device_managed_networks_id>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
resource "cloudflare_device_managed_networks" "managed_networks" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "managed-network-1"
type = "tls"
config {
tls_sockaddr = "foobar:1234"
sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
}
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ func New(version string) func() *schema.Provider {
"cloudflare_device_policy_certificates": resourceCloudflareDevicePolicyCertificates(),
"cloudflare_device_posture_integration": resourceCloudflareDevicePostureIntegration(),
"cloudflare_device_posture_rule": resourceCloudflareDevicePostureRule(),
"cloudflare_device_managed_networks": resourceCloudflareDeviceManagedNetworks(),
"cloudflare_dlp_profile": resourceCloudflareDLPProfile(),
"cloudflare_email_routing_address": resourceCloudflareEmailRoutingAddress(),
"cloudflare_email_routing_catch_all": resourceCloudflareEmailRoutingCatchAll(),
Expand Down
152 changes: 152 additions & 0 deletions internal/provider/resource_cloudflare_device_managed_networks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package provider

import (
"context"
"errors"
"fmt"
"strings"

"github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceCloudflareDeviceManagedNetworks() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareDeviceManagedNetworksSchema(),
CreateContext: resourceCloudflareDeviceManagedNetworksCreate,
ReadContext: resourceCloudflareDeviceManagedNetworksRead,
UpdateContext: resourceCloudflareDeviceManagedNetworksUpdate,
DeleteContext: resourceCloudflareDeviceManagedNetworksDelete,
Importer: &schema.ResourceImporter{
StateContext: resourceCloudflareDeviceManagedNetworksImport,
},
Description: "Provides a Cloudflare Device Managed Network resource. Device managed networks allow for building location-aware device settings policies.",
}
}

func resourceCloudflareDeviceManagedNetworksRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
identifier := cloudflare.AccountIdentifier(d.Get("account_id").(string))
tflog.Debug(ctx, fmt.Sprintf("Reading Cloudflare Device Managed Network for Id: %+v", d.Id()))

managedNetwork, err := client.GetDeviceManagedNetwork(ctx, identifier, d.Id())

var notFoundError *cloudflare.NotFoundError
if errors.As(err, &notFoundError) {
tflog.Info(ctx, fmt.Sprintf("Device Managed Network %s no longer exists", d.Id()))
d.SetId("")
return nil
}
if err != nil {
return diag.FromErr(fmt.Errorf("error reading Device Managed Network: %w", err))
}

d.Set("name", managedNetwork.Name)
d.Set("type", managedNetwork.Type)
d.Set("config", convertDeviceManagedNetworkConfigToSchema(managedNetwork.Config))

return nil
}

func resourceCloudflareDeviceManagedNetworksCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
identifier := cloudflare.AccountIdentifier(d.Get("account_id").(string))

params := cloudflare.CreateDeviceManagedNetworkParams{
Name: d.Get("name").(string),
Type: d.Get("type").(string),
Config: &cloudflare.Config{
TlsSockAddr: d.Get("config.0.tls_sockaddr").(string),
Sha256: d.Get("config.0.sha256").(string),
},
}

tflog.Debug(ctx, fmt.Sprintf("Creating Cloudflare Device Managed Network with params: %+v", params))

managedNetwork, err := client.CreateDeviceManagedNetwork(ctx, identifier, params)

if err != nil {
return diag.FromErr(fmt.Errorf("error creating Device Managed Network with provided config: %w", err))
}

d.SetId(managedNetwork.NetworkID)

return resourceCloudflareDeviceManagedNetworksRead(ctx, d, meta)
}

func resourceCloudflareDeviceManagedNetworksUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
identifier := cloudflare.AccountIdentifier(d.Get("account_id").(string))

updatedDeviceManagedNetworkParams := cloudflare.UpdateDeviceManagedNetworkParams{
NetworkID: d.Id(),
Name: d.Get("name").(string),
Type: d.Get("type").(string),
Config: &cloudflare.Config{
TlsSockAddr: d.Get("config.0.tls_sockaddr").(string),
Sha256: d.Get("config.0.sha256").(string),
},
}

tflog.Debug(ctx, fmt.Sprintf("Updating Cloudflare Device Managed Network with params: %+v", updatedDeviceManagedNetworkParams))

managedNetwork, err := client.UpdateDeviceManagedNetwork(ctx, identifier, updatedDeviceManagedNetworkParams)

if err != nil {
return diag.FromErr(fmt.Errorf("error updating Device Managed Network for ID %q: %w", d.Id(), err))
}
if managedNetwork.NetworkID == "" {
return diag.FromErr(fmt.Errorf("failed to find Network ID in update response; resource was empty"))
}

return resourceCloudflareDeviceManagedNetworksRead(ctx, d, meta)
}

func resourceCloudflareDeviceManagedNetworksDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
identifier := cloudflare.AccountIdentifier(d.Get("account_id").(string))
tflog.Debug(ctx, fmt.Sprintf("Deleting Cloudflare Device Managed Network using ID: %s", d.Id()))

if _, err := client.DeleteManagedNetworks(ctx, identifier, d.Id()); err != nil {
return diag.FromErr(fmt.Errorf("error deleting DLP Profile for ID %q: %w", d.Id(), err))
}

resourceCloudflareDeviceManagedNetworksRead(ctx, d, meta)
return nil
}

func resourceCloudflareDeviceManagedNetworksImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
accountID, managedNetworkID, err := parseDeviceManagedNetworksIDImport(d.Id())
if err != nil {
return nil, err
}

tflog.Debug(ctx, fmt.Sprintf("Importing Cloudflare Device Managed Network: id %s for account %s", managedNetworkID, accountID))

d.Set("account_id", accountID)
d.SetId(managedNetworkID)

resourceCloudflareDeviceManagedNetworksRead(ctx, d, meta)

return []*schema.ResourceData{d}, nil
}

func parseDeviceManagedNetworksIDImport(id string) (string, string, error) {
attributes := strings.SplitN(id, "/", 2)

if len(attributes) != 2 {
return "", "", fmt.Errorf("invalid id (\"%s\") specified, should be in format \"accountID/networkID\"", id)
}

return attributes[0], attributes[1], nil
}

func convertDeviceManagedNetworkConfigToSchema(input *cloudflare.Config) []interface{} {
m := map[string]interface{}{
"sha256": &input.Sha256,
"tls_sockaddr": &input.TlsSockAddr,
}
return []interface{}{m}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package provider

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccCloudflareDeviceManagedNetworks(t *testing.T) {
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_device_managed_networks.%s", rnd)

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheckAccount(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCloudflareDeviceManagedNetworks(accountID, rnd),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "account_id", accountID),
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "type", "tls"),
resource.TestCheckResourceAttr(name, "config.0.tls_sockaddr", "foobar:1234"),
resource.TestCheckResourceAttr(name, "config.0.sha256", "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"),
),
},
},
})
}

func testAccCloudflareDeviceManagedNetworks(accountID, rnd string) string {
return fmt.Sprintf(`
resource "cloudflare_device_managed_networks" "%[1]s" {
account_id = "%[2]s"
name = "%[1]s"
type = "tls"
config {
tls_sockaddr = "foobar:1234"
sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
}
}
`, rnd, accountID)
}
49 changes: 49 additions & 0 deletions internal/provider/schema_cloudflare_device_managed_networks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package provider

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceCloudflareDeviceManagedNetworksSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"account_id": {
Description: "The account identifier to target for the resource.",
Type: schema.TypeString,
Required: true,
},
"type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"tls"}, false),
Description: fmt.Sprintf("The type of Device Managed Network. %s", renderAvailableDocumentationValuesStringSlice([]string{"tls"})),
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the Device Managed Network. Must be unique.",
},
"config": {
Type: schema.TypeList,
Required: true,
Description: "The configuration containing information for the WARP client to detect the managed network.",
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"tls_sockaddr": {
Type: schema.TypeString,
Required: true,
Description: "A network address of the form \"host:port\" that the WARP client will use to detect the presence of a TLS host.",
},
"sha256": {
Type: schema.TypeString,
Required: true,
Description: "The SHA-256 hash of the TLS certificate presented by the host found at tls_sockaddr. If absent, regular certificate verification (trusted roots, valid timestamp, etc) will be used to validate the certificate.",
},
},
},
},
}
}

0 comments on commit f456811

Please sign in to comment.