Skip to content

Commit 831de93

Browse files
authored
feat(vpc): add support for private network, private nic (#649)
This adds the support of VPC resources, data sources, and instance private NIC dependency. The private NIC resource id has an unusual format like: zone/server_uuid/private_nic_uuid this is due to the implementation of the private NIC endpoint .../v1/zone/servers/server_id/private-nics/private_nic_id thus the SDK. So we have to store the server ID within the private NIC resource ID. Additional helpers for parsing/building this new format of resource ID called NestedID have been added. Signed-off-by: Amine Kherbouche <[email protected]>
1 parent 9f85bde commit 831de93

16 files changed

+5798
-0
lines changed
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
page_title: "Scaleway: scaleway_vpc_private_network"
3+
description: |-
4+
Get information about Scaleway VPC Private Networks.
5+
---
6+
7+
# scaleway_vpc_private_network
8+
9+
Gets information about a private network.
10+
11+
## Example Usage
12+
13+
N/A, the usage will be meaningful in the next releases of VPC.
14+
15+
## Argument Reference
16+
17+
* `name` - (Required) Exact name of the private network.
18+
19+
## Attributes Reference
20+
21+
`id` is set to the ID of the found private network. Addition attributes are
22+
exported.
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
page_title: "Scaleway: scaleway_instance_private_nic"
3+
description: |-
4+
Manages Scaleway Compute Instance Private NICs.
5+
---
6+
7+
# scaleway_instance_private_nic
8+
9+
Creates and manages Scaleway Instance Private NICs. For more information, see
10+
[the documentation](https://developers.scaleway.com/en/products/instance/api/#private-nics-a42eea).
11+
12+
## Example
13+
14+
```hcl
15+
resource "scaleway_instance_private_nic" "pnic01" {
16+
server_id = "fr-par-1/11111111-1111-1111-1111-111111111111"
17+
private_network_id = "fr-par-1/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
18+
}
19+
```
20+
21+
## Arguments Reference
22+
23+
The following arguments are required:
24+
25+
- `server_id` - (Required) The ID of the server associated with.
26+
- `private_network_id` - (Required) The ID of the private network attached to.
27+
28+
## Attributes Reference
29+
30+
In addition to all above arguments, the following attributes are exported:
31+
32+
- `id` - The ID of the private NIC.
33+
34+
## Import
35+
36+
Private NICs can be imported using the `{zone}/{server_id}/{private_nic_id}`, e.g.
37+
38+
```bash
39+
$ terraform import scaleway_instance_volume.server_volume fr-par-1/11111111-1111-1111-1111-111111111111/22222222-2222-2222-2222-222222222222
40+
```

docs/resources/vpc_private_network.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
page_title: "Scaleway: scaleway_vpc_private_network"
3+
description: |-
4+
Manages Scaleway VPC Private Networks.
5+
---
6+
7+
# scaleway_vpc_private_network
8+
9+
Creates and manages Scaleway VPC Private Networks. For more information, see
10+
[the documentation](https://developers.scaleway.com/en/products/vpc/api/#private-networks-ac2df4).
11+
12+
## Example
13+
14+
```hcl
15+
resource "scaleway_vpc_private_network" "pn_priv" {
16+
name = "subnet_demo"
17+
tags = ["demo", "tarraform"]
18+
}
19+
```
20+
21+
## Arguments Reference
22+
23+
The following arguments are supported:
24+
25+
- `name` - (Optional) The name of the private network. If not provided it will be randomly generated.
26+
- `tags` - (Optional) The tags associated with the private network.
27+
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the private network should be created.
28+
- `project_id` - (Defaults to [provider](../index.md#project_id) `project_id`) The ID of the project the private network is associated with.
29+
30+
## Attributes Reference
31+
32+
In addition to all above arguments, the following attributes are exported:
33+
34+
- `id` - The ID of the private network.
35+
- `organization_id` - (Defaults to [provider](../index.md#organization_id) `organization_id`) The ID of the organization the private network is associated with.
36+
37+
## Import
38+
39+
Private networks can be imported using the `{zone}/{id}`, e.g.
40+
41+
```bash
42+
$ terraform import scaleway_vpc_private_network.vpc_demo fr-par-1/11111111-1111-1111-1111-111111111111
43+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package scaleway
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/scaleway/scaleway-sdk-go/api/vpc/v1"
10+
"github.com/scaleway/scaleway-sdk-go/scw"
11+
)
12+
13+
func dataSourceScalewayVPCPrivateNetwork() *schema.Resource {
14+
// Generate datasource schema from resource
15+
dsSchema := datasourceSchemaFromResourceSchema(resourceScalewayVPCPrivateNetwork().Schema)
16+
17+
// Set 'Optional' schema elements
18+
addOptionalFieldsToSchema(dsSchema, "name")
19+
20+
dsSchema["name"].ConflictsWith = []string{"private_network_id"}
21+
dsSchema["private_network_id"] = &schema.Schema{
22+
Type: schema.TypeString,
23+
Optional: true,
24+
Description: "The ID of the private network",
25+
ValidateFunc: validationUUIDorUUIDWithLocality(),
26+
ConflictsWith: []string{"name"},
27+
}
28+
29+
return &schema.Resource{
30+
Schema: dsSchema,
31+
ReadContext: dataSourceScalewayVPCPrivateNetworkRead,
32+
}
33+
}
34+
35+
func dataSourceScalewayVPCPrivateNetworkRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
36+
meta := m.(*Meta)
37+
vpcAPI, zone, err := vpcAPIWithZone(d, meta)
38+
if err != nil {
39+
return diag.FromErr(err)
40+
}
41+
42+
privateNetworkID, ok := d.GetOk("private_network_id")
43+
if !ok {
44+
res, err := vpcAPI.ListPrivateNetworks(
45+
&vpc.ListPrivateNetworksRequest{
46+
Name: expandStringPtr(d.Get("name").(string)),
47+
Zone: zone,
48+
}, scw.WithContext(ctx))
49+
if err != nil {
50+
return diag.FromErr(err)
51+
}
52+
if res.TotalCount == 0 {
53+
return diag.FromErr(
54+
fmt.Errorf(
55+
"no private network found with the name %s",
56+
d.Get("name"),
57+
),
58+
)
59+
}
60+
if res.TotalCount > 1 {
61+
return diag.FromErr(
62+
fmt.Errorf(
63+
"%d private networks found with the name %s",
64+
res.TotalCount,
65+
d.Get("name"),
66+
),
67+
)
68+
}
69+
privateNetworkID = res.PrivateNetworks[0].ID
70+
}
71+
72+
zonedID := datasourceNewZonedID(privateNetworkID, zone)
73+
d.SetId(zonedID)
74+
_ = d.Set("private_network_id", zonedID)
75+
return resourceScalewayVPCPrivateNetworkRead(ctx, d, m)
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
)
9+
10+
func TestAccScalewayDataSourceVPCPrivateNetwork_Basic(t *testing.T) {
11+
tt := NewTestTools(t)
12+
defer tt.Cleanup()
13+
pnName := "TestAccScalewayDataSourceVPCPrivateNetwork_Basic"
14+
resource.ParallelTest(t, resource.TestCase{
15+
PreCheck: func() { testAccPreCheck(t) },
16+
ProviderFactories: tt.ProviderFactories,
17+
CheckDestroy: testAccCheckScalewayVPCPrivateNetworkDestroy(tt),
18+
Steps: []resource.TestStep{
19+
{
20+
Config: fmt.Sprintf(`
21+
resource "scaleway_vpc_private_network" "pn_test" {
22+
name = "%s"
23+
}`, pnName),
24+
},
25+
{
26+
Config: fmt.Sprintf(`
27+
resource "scaleway_vpc_private_network" "pn_test" {
28+
name = "%s"
29+
}
30+
31+
data "scaleway_vpc_private_network" "pn_test_by_name" {
32+
name = "${scaleway_vpc_private_network.pn_test.name}"
33+
}
34+
35+
data "scaleway_vpc_private_network" "pn_test_by_id" {
36+
private_network_id = "${scaleway_vpc_private_network.pn_test.id}"
37+
}
38+
`, pnName),
39+
Check: resource.ComposeTestCheckFunc(
40+
testAccCheckScalewayVPCPrivateNetworkExists(tt, "scaleway_vpc_private_network.pn_test"),
41+
resource.TestCheckResourceAttrPair(
42+
"data.scaleway_vpc_private_network.pn_test_by_name", "name",
43+
"scaleway_vpc_private_network.pn_test", "name"),
44+
resource.TestCheckResourceAttrPair(
45+
"data.scaleway_vpc_private_network.pn_test_by_id", "private_network_id",
46+
"scaleway_vpc_private_network.pn_test", "id"),
47+
),
48+
},
49+
},
50+
})
51+
}

scaleway/helpers.go

+25
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ func parseLocalizedID(localizedID string) (locality string, ID string, err error
9090
return tab[0], tab[1], nil
9191
}
9292

93+
// parseLocalizedNestedID parses a localizedNestedID and extracts the resource locality, the inner and outer id.
94+
func parseLocalizedNestedID(localizedID string) (locality string, innerID, outerID string, err error) {
95+
tab := strings.SplitN(localizedID, "/", -1)
96+
if len(tab) != 3 {
97+
return "", "", localizedID, fmt.Errorf("cant parse localized id: %s", localizedID)
98+
}
99+
return tab[0], tab[1], tab[2], nil
100+
}
101+
93102
// parseZonedID parses a zonedID and extracts the resource zone and id.
94103
func parseZonedID(zonedID string) (zone scw.Zone, id string, err error) {
95104
locality, id, err := parseLocalizedID(zonedID)
@@ -101,6 +110,17 @@ func parseZonedID(zonedID string) (zone scw.Zone, id string, err error) {
101110
return
102111
}
103112

113+
// parseZonedNestedID parses a zonedNestedID and extracts the resource zone ,inner and outer ID.
114+
func parseZonedNestedID(zonedNestedID string) (zone scw.Zone, outerID, innerID string, err error) {
115+
locality, innerID, outerID, err := parseLocalizedNestedID(zonedNestedID)
116+
if err != nil {
117+
return
118+
}
119+
120+
zone, err = scw.ParseZone(locality)
121+
return
122+
}
123+
104124
// expandID returns the id whether it is a localizedID or a raw ID.
105125
func expandID(id interface{}) string {
106126
_, ID, err := parseLocalizedID(id.(string))
@@ -126,6 +146,11 @@ func newZonedIDString(zone scw.Zone, id string) string {
126146
return fmt.Sprintf("%s/%s", zone, id)
127147
}
128148

149+
// newZonedNestedIDString constructs a unique identifier based on resource zone, inner and outer IDs
150+
func newZonedNestedIDString(zone scw.Zone, outerID, innerID string) string {
151+
return fmt.Sprintf("%s/%s/%s", zone, outerID, innerID)
152+
}
153+
129154
// newRegionalIDString constructs a unique identifier based on resource region and id
130155
func newRegionalIDString(region scw.Region, id string) string {
131156
return fmt.Sprintf("%s/%s", region, id)

scaleway/helpers_instance.go

+9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ func instanceAPIWithZoneAndID(m interface{}, zonedID string) (*instance.API, scw
3939
return instanceAPI, zone, ID, err
4040
}
4141

42+
// instanceAPIWithZoneAndNestedID returns an instance API with zone and inner/outer ID extracted from the state
43+
func instanceAPIWithZoneAndNestedID(m interface{}, zonedNestedID string) (*instance.API, scw.Zone, string, string, error) {
44+
meta := m.(*Meta)
45+
instanceAPI := instance.NewAPI(meta.scwClient)
46+
47+
zone, innerID, outerID, err := parseZonedNestedID(zonedNestedID)
48+
return instanceAPI, zone, innerID, outerID, err
49+
}
50+
4251
// hash hashes a string to a unique hashcode.
4352
//
4453
// crc32 returns a uint32, but for our use we need

scaleway/helpers_vpc.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package scaleway
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5+
vpc "github.com/scaleway/scaleway-sdk-go/api/vpc/v1"
6+
"github.com/scaleway/scaleway-sdk-go/scw"
7+
)
8+
9+
// vpcAPIWithZone returns a new VPC API and the zone for a Create request
10+
func vpcAPIWithZone(d *schema.ResourceData, m interface{}) (*vpc.API, scw.Zone, error) {
11+
meta := m.(*Meta)
12+
vpcAPI := vpc.NewAPI(meta.scwClient)
13+
14+
zone, err := extractZone(d, meta)
15+
return vpcAPI, zone, err
16+
}
17+
18+
// vpcAPIWithZoneAndID
19+
func vpcAPIWithZoneAndID(m interface{}, id string) (*vpc.API, scw.Zone, string, error) {
20+
meta := m.(*Meta)
21+
vpcAPI := vpc.NewAPI(meta.scwClient)
22+
23+
zone, ID, err := parseZonedID(id)
24+
return vpcAPI, zone, ID, err
25+
}

scaleway/provider.go

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
7575
"scaleway_instance_security_group_rules": resourceScalewayInstanceSecurityGroupRules(),
7676
"scaleway_instance_server": resourceScalewayInstanceServer(),
7777
"scaleway_instance_placement_group": resourceScalewayInstancePlacementGroup(),
78+
"scaleway_instance_private_nic": resourceScalewayInstancePrivateNIC(),
7879
"scaleway_k8s_cluster": resourceScalewayK8SCluster(),
7980
"scaleway_k8s_pool": resourceScalewayK8SPool(),
8081
"scaleway_lb": resourceScalewayLb(),
@@ -86,6 +87,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
8687
"scaleway_rdb_instance": resourceScalewayRdbInstance(),
8788
"scaleway_rdb_user": resourceScalewayRdbUser(),
8889
"scaleway_object_bucket": resourceScalewayObjectBucket(),
90+
"scaleway_vpc_private_network": resourceScalewayVPCPrivateNetwork(),
8991
},
9092

9193
DataSourcesMap: map[string]*schema.Resource{
@@ -100,6 +102,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
100102
"scaleway_marketplace_image": dataSourceScalewayMarketplaceImage(),
101103
"scaleway_registry_namespace": dataSourceScalewayRegistryNamespace(),
102104
"scaleway_registry_image": dataSourceScalewayRegistryImage(),
105+
"scaleway_vpc_private_network": dataSourceScalewayVPCPrivateNetwork(),
103106
},
104107
}
105108

0 commit comments

Comments
 (0)