Skip to content

Commit

Permalink
Add support for virtual networks
Browse files Browse the repository at this point in the history
  • Loading branch information
vavsab committed Jun 3, 2022
1 parent aeee4ae commit 56f9506
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 2 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,6 @@ require (
// Use custom version that supports configuration as flags and newer tfexec
// until it lands upstream.
replace github.com/hashicorp/terraform-plugin-docs v0.5.1 => github.com/jacobbednarz/terraform-plugin-docs v0.5.1-0.20220314024219-d04ad37d2ee8

// TODO: Remove when fix is released
replace github.com/cloudflare/cloudflare-go => github.com/mapped/cloudflare-go v0.40.1-0.20220603175700-567edc574e2c
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,6 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.40.0 h1:OjW+SYY7+NVSTj+/6kORqvu33LH7uZ0hUd/0qOqucxU=
github.com/cloudflare/cloudflare-go v0.40.0/go.mod h1:MmAqiRfD8rjKEuUe4MYNHfHjYhFWfW7PNe12CCQWqPY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
Expand Down Expand Up @@ -703,6 +701,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mapped/cloudflare-go v0.40.1-0.20220603175700-567edc574e2c h1:v0hceaBjJoeUHe6/Vd2SsDfK+EShdmX+Y7GutLYY+zs=
github.com/mapped/cloudflare-go v0.40.1-0.20220603175700-567edc574e2c/go.mod h1:MmAqiRfD8rjKEuUe4MYNHfHjYhFWfW7PNe12CCQWqPY=
github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKoALdbQ=
github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA=
Expand Down
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func New(version string) func() *schema.Provider {
"cloudflare_teams_rule": resourceCloudflareTeamsRule(),
"cloudflare_teams_proxy_endpoint": resourceCloudflareTeamsProxyEndpoint(),
"cloudflare_tunnel_route": resourceCloudflareTunnelRoute(),
"cloudflare_tunnel_virtual_network": resourceCloudflareTunnelVirtualNetwork(),
"cloudflare_waf_group": resourceCloudflareWAFGroup(),
"cloudflare_waf_override": resourceCloudflareWAFOverride(),
"cloudflare_waf_package": resourceCloudflareWAFPackage(),
Expand Down
137 changes: 137 additions & 0 deletions internal/provider/resource_cloudflare_tunnel_virtual_network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
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 resourceCloudflareTunnelVirtualNetwork() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareTunnelVirtualNetworkSchema(),
CreateContext: resourceCloudflareTunnelVirtualNetworkCreate,
ReadContext: resourceCloudflareTunnelVirtualNetworkRead,
UpdateContext: resourceCloudflareTunnelVirtualNetworkUpdate,
DeleteContext: resourceCloudflareTunnelVirtualNetworkDelete,
Importer: &schema.ResourceImporter{
StateContext: resourceCloudflareTunnelVirtualNetworkImport,
},
}
}

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

tunnelVirtualNetworks, err := client.ListTunnelVirtualNetworks(ctx, cloudflare.TunnelVirtualNetworksListParams{
AccountID: accountID,
IsDeleted: cloudflare.BoolPtr(false),
ID: d.Id(),
})

if err != nil {
return diag.FromErr(fmt.Errorf("failed to fetch Tunnel Virtual Network: %w", err))
}

if len(tunnelVirtualNetworks) < 1 {
tflog.Info(ctx, fmt.Sprintf("Tunnel Virtual Network for ID %s in account %s not found", d.Id(), accountID))
d.SetId("")
return nil
}

tunnelVirtualNetwork := tunnelVirtualNetworks[0]

d.Set("name", tunnelVirtualNetwork.Name)
d.Set("is_default_network", tunnelVirtualNetwork.IsDefaultNetwork)

if len(tunnelVirtualNetwork.Comment) > 0 {
d.Set("comment", tunnelVirtualNetwork.Comment)
}

return nil
}

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

resource := cloudflare.TunnelVirtualNetworkCreateParams{
AccountID: d.Get("account_id").(string),
Name: name,
IsDefault: d.Get("is_default_network").(bool),
}

if comment, ok := d.Get("comment").(string); ok {
resource.Comment = comment
}

newTunnelVirtualNetwork, err := client.CreateTunnelVirtualNetwork(ctx, resource)
if err != nil {
return diag.FromErr(fmt.Errorf("error creating Tunnel Virtual Network %q: %w", name, err))
}

d.SetId(newTunnelVirtualNetwork.ID)

return resourceCloudflareTunnelVirtualNetworkRead(ctx, d, meta)
}

func resourceCloudflareTunnelVirtualNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)

resource := cloudflare.TunnelVirtualNetworkUpdateParams{
AccountID: d.Get("account_id").(string),
Name: d.Get("name").(string),
IsDefaultNetwork: cloudflare.BoolPtr(d.Get("is_default_network").(bool)),
}

if comment, ok := d.Get("comment").(string); ok {
resource.Comment = comment
}

_, err := client.UpdateTunnelVirtualNetwork(ctx, resource)
if err != nil {
return diag.FromErr(fmt.Errorf("error updating Tunnel Virtual Network %q: %w", d.Id(), err))
}

return resourceCloudflareTunnelVirtualNetworkRead(ctx, d, meta)
}

func resourceCloudflareTunnelVirtualNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)

err := client.DeleteTunnelVirtualNetwork(ctx, cloudflare.TunnelVirtualNetworkDeleteParams{
AccountID: d.Get("account_id").(string),
VnetID: d.Id(),
})
if err != nil {
return diag.FromErr(fmt.Errorf("error deleting Tunnel Virtual Network %q: %w", d.Id(), err))
}

return nil
}

func resourceCloudflareTunnelVirtualNetworkImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
attributes := strings.SplitN(d.Id(), "/", 2)

if len(attributes) != 2 {
return nil, fmt.Errorf(`invalid id (%q) specified, should be in format "accountID/vnetID"`, d.Id())
}

accountID, vnetID := attributes[0], attributes[1]

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

err := resourceCloudflareTunnelVirtualNetworkRead(ctx, d, meta)
if err != nil {
return nil, errors.New("failed to read Tunnel Virtual Network state")
}

return []*schema.ResourceData{d}, nil
}
152 changes: 152 additions & 0 deletions internal/provider/resource_cloudflare_tunnel_virtual_network_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package provider

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

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

func init() {
resource.AddTestSweepers("cloudflare_tunnel_virtual_network", &resource.Sweeper{
Name: "cloudflare_tunnel_virtual_network",
F: testSweepCloudflareTunnelVirtualNetwork,
})
}

func testSweepCloudflareTunnelVirtualNetwork(r string) error {
ctx := context.Background()
client, clientErr := sharedClient()
if clientErr != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to create Cloudflare client: %s", clientErr))
}

accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
if accountID == "" {
return errors.New("CLOUDFLARE_ACCOUNT_ID must be set")
}

tunnelVirtualNetworks, err := client.ListTunnelVirtualNetworks(context.Background(), cloudflare.TunnelVirtualNetworksListParams{AccountID: accountID})
if err != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to fetch Cloudflare Tunnel Virtual Networks: %s", err))
}

if len(tunnelVirtualNetworks) == 0 {
log.Print("[DEBUG] No Cloudflare Tunnel Virtual Networks to sweep")
return nil
}

for _, vnet := range tunnelVirtualNetworks {
tflog.Info(ctx, fmt.Sprintf("Deleting Cloudflare Tunnel Virtual Network %s", vnet.ID))
//nolint:errcheck
client.DeleteTunnelVirtualNetwork(context.Background(), cloudflare.TunnelVirtualNetworkDeleteParams{AccountID: accountID, VnetID: vnet.ID})
}

return nil
}

func TestAccCloudflareTunnelVirtualNetwork_Exists(t *testing.T) {
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_tunnel_virtual_network.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")

var TunnelVirtualNetwork cloudflare.TunnelVirtualNetwork

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAccount(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCloudflareTunnelVirtualNetworkSimple(rnd, rnd, accountID, rnd, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareTunnelVirtualNetworkExists(name, &TunnelVirtualNetwork),
resource.TestCheckResourceAttr(name, "account_id", accountID),
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "comment", rnd),
resource.TestCheckResourceAttr(name, "is_default_network", "false"),
),
},
},
})
}

func testAccCheckCloudflareTunnelVirtualNetworkExists(name string, virtualNetwork *cloudflare.TunnelVirtualNetwork) resource.TestCheckFunc {

return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}

if rs.Primary.ID == "" {
return errors.New("No Tunnel Virtual Network is set")
}

client := testAccProvider.Meta().(*cloudflare.API)
foundTunnelVirtualNetworks, err := client.ListTunnelVirtualNetworks(context.Background(), cloudflare.TunnelVirtualNetworksListParams{
AccountID: rs.Primary.Attributes["account_id"],
IsDeleted: cloudflare.BoolPtr(false),
ID: rs.Primary.ID,
})

if err != nil {
return err
}

*virtualNetwork = foundTunnelVirtualNetworks[0]

return nil
}
}

func TestAccCloudflareTunnelVirtualNetwork_UpdateComment(t *testing.T) {
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_tunnel_virtual_network.%s", rnd)
accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")

var TunnelVirtualNetwork cloudflare.TunnelVirtualNetwork

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAccount(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCloudflareTunnelVirtualNetworkSimple(rnd, rnd, accountID, rnd, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareTunnelVirtualNetworkExists(name, &TunnelVirtualNetwork),
resource.TestCheckResourceAttr(name, "comment", rnd),
),
},
{
Config: testAccCloudflareTunnelVirtualNetworkSimple(rnd, rnd+"-updated", accountID, rnd, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareTunnelVirtualNetworkExists(name, &TunnelVirtualNetwork),
resource.TestCheckResourceAttr(name, "comment", rnd+"-updated"),
),
},
},
})
}

func testAccCloudflareTunnelVirtualNetworkSimple(ID, comment, accountID, name string, isDefault bool) string {
return fmt.Sprintf(`
resource "cloudflare_tunnel_virtual_network" "%[1]s" {
account_id = "%[3]s"
name = "%[4]s"
comment = "%[2]s"
is_default_network = "%[5]t"
}`, ID, comment, accountID, name, isDefault)
}
27 changes: 27 additions & 0 deletions internal/provider/schema_cloudflare_tunnel_virtual_network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package provider

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

func resourceCloudflareTunnelVirtualNetworkSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
},
"is_default_network": {
Type: schema.TypeBool,
Optional: true,
},
"comment": {
Type: schema.TypeString,
Optional: true,
},
}
}
3 changes: 3 additions & 0 deletions website/cloudflare.erb
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@
<li<%= sidebar_current("docs-cloudflare-tunnel-route") %>>
<a href="/docs/providers/cloudflare/r/tunnel_route.html">cloudflare_tunnel_route</a>
</li>
<li<%= sidebar_current("ddocs-cloudflare-tunnel-virtual_network") %>>
<a href="/docs/providers/cloudflare/r/tunnel_virtual_network.html">cloudflare_tunnel_virtual_network</a>
</li>
<li<%= sidebar_current("docs-cloudflare-resource-waf-group") %>>
<a href="/docs/providers/cloudflare/r/waf_group.html">cloudflare_waf_group</a>
</li>
Expand Down
Loading

0 comments on commit 56f9506

Please sign in to comment.