Skip to content

Commit

Permalink
feat(vpcgw): add gateway network resource (scaleway#891)
Browse files Browse the repository at this point in the history
Co-authored-by: scaleway-bot <[email protected]>
  • Loading branch information
Monitob and scaleway-bot authored Oct 11, 2021
1 parent a3a0daf commit cdaf87a
Show file tree
Hide file tree
Showing 11 changed files with 4,247 additions and 92 deletions.
69 changes: 69 additions & 0 deletions docs/resources/vpc_gateway_network.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
page_title: "Scaleway: scaleway_vpc_gateway_network"
description: |-
Manages Scaleway VPC Gateway Networks.
---

# scaleway_vpc_gateway_network

Creates and manages Scaleway VPC Public Gateway Network.
It allows attaching Private Networks to the VPC Public Gateway and your DHCP config
For more information, see [the documentation](https://developers.scaleway.com/en/products/vpc-gw/api/#step-3-attach-private-networks-to-the-vpc-public-gateway).

## Example

```hcl
resource scaleway_vpc_private_network pn01 {
name = "pn_test_network"
}
resource scaleway_vpc_public_gateway_ip gw01 {
}
resource scaleway_vpc_public_gateway_dhcp dhcp01 {
subnet = "192.168.1.0/24"
}
resource scaleway_vpc_public_gateway pg01 {
name = "foobar"
type = "VPC-GW-S"
ip_id = scaleway_vpc_public_gateway_ip.gw01.id
}
resource scaleway_vpc_gateway_network main {
gateway_id = scaleway_vpc_public_gateway.pg01.id
private_network_id = scaleway_vpc_private_network.pn01.id
dhcp_id = scaleway_vpc_public_gateway_dhcp.dhcp01.id
}
```

## Arguments Reference

The following arguments are supported:

- `gateway_id` - (Required) The ID of the public gateway.
- `private_network_id` - (Required) The ID of the private network.
- `dhcp_id` - (Required) The ID of the public gateway DHCP config.
- `enable_masquerade` - (Defaults to false) Enable masquerade on this network
- `enable_dhcp` - (Defaults to true) Enable DHCP config on this network. It requires DHCP id.
- `static_address` - Enable DHCP config on this network
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the gateway network should be created.
- `project_id` - (Defaults to [provider](../index.md#project_id) `project_id`) The ID of the project the gateway network is associated with.

## Attributes Reference

In addition to all above arguments, the following attributes are exported:

- `id` - The ID of the gateway network.
- `mac_address` - The mac address of the creation of the gateway network.
- `created_at` - The date and time of the creation of the gateway network.
- `updated_at` - The date and time of the last update of the gateway network.

## Import

Gateway network can be imported using the `{zone}/{id}`, e.g.

```bash
$ terraform import scaleway_vpc_gateway_network.main fr-par-1/11111111-1111-1111-1111-111111111111
```

3 changes: 2 additions & 1 deletion scaleway/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/scaleway/scaleway-sdk-go/scw"
)

// Provider config can be used to provide additional config when creating provider.
// ProviderConfig config can be used to provide additional config when creating provider.
type ProviderConfig struct {
// Meta can be used to override Meta that will be used by the provider.
// This is useful for tests.
Expand Down Expand Up @@ -92,6 +92,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
"scaleway_rdb_user": resourceScalewayRdbUser(),
"scaleway_object_bucket": resourceScalewayObjectBucket(),
"scaleway_vpc_public_gateway": resourceScalewayVPCPublicGateway(),
"scaleway_vpc_gateway_network": resourceScalewayVPCGatewayNetwork(),
"scaleway_vpc_public_gateway_dhcp": resourceScalewayVPCPublicGatewayDHCP(),
"scaleway_vpc_public_gateway_ip": resourceScalewayVPCPublicGatewayIP(),
"scaleway_vpc_private_network": resourceScalewayVPCPrivateNetwork(),
Expand Down
256 changes: 256 additions & 0 deletions scaleway/resource_vpc_gateway_network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
package scaleway

import (
"context"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
vpcgw "github.com/scaleway/scaleway-sdk-go/api/vpcgw/v1beta1"
"github.com/scaleway/scaleway-sdk-go/scw"
)

const (
retryIntervalVPCGatewayNetwork = 30 * time.Second
cleanUpDHCP = true
)

func resourceScalewayVPCGatewayNetwork() *schema.Resource {
return &schema.Resource{
CreateContext: resourceScalewayVPCGatewayNetworkCreate,
ReadContext: resourceScalewayVPCGatewayNetworkRead,
UpdateContext: resourceScalewayVPCGatewayNetworkUpdate,
DeleteContext: resourceScalewayVPCGatewayNetworkDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"gateway_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validationUUIDorUUIDWithLocality(),
Description: "The ID of the public gateway where connect to",
},
"private_network_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validationUUIDorUUIDWithLocality(),
Description: "The ID of the private network where connect to",
},
"dhcp_id": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validationUUIDorUUIDWithLocality(),
Description: "The ID of the public gateway DHCP config",
},
"enable_masquerade": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Enable masquerade on this network",
},
"enable_dhcp": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Enable DHCP config on this network",
},
"static_address": {
Type: schema.TypeString,
Description: "The static IP address in CIDR on this network",
Optional: true,
ValidateFunc: validation.IsCIDR,
},
// Computed elements
"mac_address": {
Type: schema.TypeString,
Computed: true,
Description: "The mac address on this network",
},
"created_at": {
Type: schema.TypeString,
Computed: true,
Description: "The date and time of the creation of the gateway network",
},
"updated_at": {
Type: schema.TypeString,
Computed: true,
Description: "The date and time of the last update of the gateway network",
},
"zone": zoneSchema(),
},
}
}

func resourceScalewayVPCGatewayNetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vpcgwNetworkAPI, zone, err := vpcgwAPIWithZone(d, meta)
if err != nil {
return diag.FromErr(err)
}

gatewayID := expandZonedID(d.Get("gateway_id").(string)).ID
req := &vpcgw.CreateGatewayNetworkRequest{
Zone: zone,
GatewayID: gatewayID,
PrivateNetworkID: expandZonedID(d.Get("private_network_id").(string)).ID,
EnableMasquerade: *expandBoolPtr(d.Get("enable_masquerade")),
EnableDHCP: expandBoolPtr(d.Get("enable_dhcp")),
}

staticAddress, staticAddressExist := d.GetOk("static_address")
if staticAddressExist {
address := expandIPNet(staticAddress.(string))
req.Address = &address
}

dhcpID, dhcpExist := d.GetOk("dhcp_id")
if dhcpExist {
dhcpZoned := expandZonedID(dhcpID.(string))
req.DHCPID = &dhcpZoned.ID
}

retryInterval := retryIntervalVPCGatewayNetwork
//check gateway is in stable state.
_, err = vpcgwNetworkAPI.WaitForGateway(&vpcgw.WaitForGatewayRequest{
GatewayID: gatewayID,
Zone: zone,
Timeout: scw.TimeDurationPtr(gatewayWaitForTimeout),
RetryInterval: &retryInterval,
}, scw.WithContext(ctx))

if err != nil && !is404Error(err) {
return diag.FromErr(err)
}
res, err := vpcgwNetworkAPI.CreateGatewayNetwork(req, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

d.SetId(newZonedIDString(zone, res.ID))
// set default interval
_, err = vpcgwNetworkAPI.WaitForGatewayNetwork(&vpcgw.WaitForGatewayNetworkRequest{
GatewayNetworkID: res.ID,
Timeout: scw.TimeDurationPtr(defaultVPCGatewayTimeout),
RetryInterval: &retryInterval,
Zone: zone,
}, scw.WithContext(ctx))
// check err waiting process
if err != nil {
return diag.FromErr(err)
}

return resourceScalewayVPCGatewayNetworkRead(ctx, d, meta)
}

func resourceScalewayVPCGatewayNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vpcgwNetworkAPI, zone, ID, err := vpcgwAPIWithZoneAndID(meta, d.Id())
if err != nil {
return diag.FromErr(err)
}

gatewayNetwork, err := vpcgwNetworkAPI.GetGatewayNetwork(&vpcgw.GetGatewayNetworkRequest{
GatewayNetworkID: ID,
Zone: zone,
}, scw.WithContext(ctx))
if err != nil {
if is404Error(err) {
d.SetId("")
return nil
}
return diag.FromErr(err)
}

if dhcp := gatewayNetwork.DHCP; dhcp != nil {
_ = d.Set("dhcp_id", newZonedID(zone, dhcp.ID).String())
}

if staticAddress := gatewayNetwork.Address; staticAddress != nil {
_ = d.Set("static_address", flattenIPNet(*staticAddress))
}

if macAddress := gatewayNetwork.MacAddress; macAddress != nil {
_ = d.Set("mac_address", flattenStringPtr(macAddress).(string))
}

_ = d.Set("gateway_id", newZonedID(zone, gatewayNetwork.GatewayID).String())
_ = d.Set("private_network_id", newZonedID(zone, gatewayNetwork.PrivateNetworkID).String())
_ = d.Set("enable_masquerade", gatewayNetwork.EnableMasquerade)
_ = d.Set("enable_dhcp", gatewayNetwork.EnableDHCP)
_ = d.Set("created_at", gatewayNetwork.CreatedAt.Format(time.RFC3339))
_ = d.Set("updated_at", gatewayNetwork.UpdatedAt.Format(time.RFC3339))
_ = d.Set("zone", zone.String())

return nil
}

func resourceScalewayVPCGatewayNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vpcgwAPI, zone, ID, err := vpcgwAPIWithZoneAndID(meta, d.Id())
if err != nil {
return diag.FromErr(err)
}

if d.HasChanges("enable_masquerade", "dhcp_id", "enable_dhcp", "static_address") {
dhcpID := expandZonedID(d.Get("dhcp_id").(string)).ID
updateRequest := &vpcgw.UpdateGatewayNetworkRequest{
GatewayNetworkID: ID,
Zone: zone,
EnableMasquerade: expandBoolPtr(d.Get("enable_masquerade")),
EnableDHCP: expandBoolPtr(d.Get("enable_dhcp")),
DHCPID: &dhcpID,
}
staticAddress, staticAddressExist := d.GetOk("static_address")
if staticAddressExist {
address := expandIPNet(staticAddress.(string))
updateRequest.Address = &address
}

_, err = vpcgwAPI.UpdateGatewayNetwork(updateRequest, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}
}

return resourceScalewayVPCGatewayNetworkRead(ctx, d, meta)
}

func resourceScalewayVPCGatewayNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vpcgwAPI, zone, ID, err := vpcgwAPIWithZoneAndID(meta, d.Id())
if err != nil {
return diag.FromErr(err)
}

defaultInterval := retryIntervalVPCGatewayNetwork
// check if network is a stable process
gwNetwork, err := vpcgwAPI.WaitForGatewayNetwork(&vpcgw.WaitForGatewayNetworkRequest{
GatewayNetworkID: ID,
Zone: zone,
RetryInterval: &defaultInterval,
})
if err != nil && !is404Error(err) {
return diag.FromErr(err)
}
//check gateway is in stable state.
_, err = vpcgwAPI.WaitForGateway(&vpcgw.WaitForGatewayRequest{
GatewayID: gwNetwork.GatewayID,
Zone: zone,
Timeout: scw.TimeDurationPtr(gatewayWaitForTimeout),
RetryInterval: &defaultInterval,
}, scw.WithContext(ctx))
if err != nil && !is404Error(err) {
return diag.FromErr(err)
}

err = vpcgwAPI.DeleteGatewayNetwork(&vpcgw.DeleteGatewayNetworkRequest{
GatewayNetworkID: ID,
Zone: zone,
CleanupDHCP: cleanUpDHCP,
}, scw.WithContext(ctx))

if err != nil && !is404Error(err) {
return diag.FromErr(err)
}

return nil
}
Loading

0 comments on commit cdaf87a

Please sign in to comment.