Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(rdb): private network update from ipam service #2068

Merged
merged 8 commits into from
Jul 27, 2023
60 changes: 0 additions & 60 deletions scaleway/helpers_rdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package scaleway
import (
"context"
"fmt"
"reflect"
"strings"
"time"

Expand Down Expand Up @@ -148,65 +147,6 @@ func expandLoadBalancer() []*rdb.EndpointSpec {
return res
}

func endpointsToRemove(endPoints []*rdb.Endpoint, updates interface{}) (map[string]bool, error) {
actions := make(map[string]bool)
endpoints := make(map[string]*rdb.Endpoint)
for _, e := range endPoints {
// skip load balancer
if e.PrivateNetwork != nil {
actions[e.ID] = true
endpoints[newZonedIDString(e.PrivateNetwork.Zone, e.PrivateNetwork.PrivateNetworkID)] = e
}
}

// compare if private networks are persisted
for _, raw := range updates.([]interface{}) {
r := raw.(map[string]interface{})
pnZonedID := r["pn_id"].(string)
locality, id, err := parseLocalizedID(pnZonedID)
if err != nil {
return nil, err
}

pnUpdated, err := newEndPointPrivateNetworkDetails(id, r["ip_net"].(string), locality)
if err != nil {
return nil, err
}
endpoint, exist := endpoints[pnZonedID]
if !exist {
continue
}
// match the endpoint id for a private network
actions[endpoint.ID] = !isEndPointEqual(endpoints[pnZonedID].PrivateNetwork, pnUpdated)
}

return actions, nil
}

func newEndPointPrivateNetworkDetails(id, ip, locality string) (*rdb.EndpointPrivateNetworkDetails, error) {
serviceIP, err := expandIPNet(ip)
if err != nil {
return nil, err
}
return &rdb.EndpointPrivateNetworkDetails{
PrivateNetworkID: id,
ServiceIP: serviceIP,
Zone: scw.Zone(locality),
}, nil
}

func isEndPointEqual(a, b interface{}) bool {
// Find out the diff Private Network or not
if _, ok := a.(*rdb.EndpointPrivateNetworkDetails); ok {
if _, ok := b.(*rdb.EndpointPrivateNetworkDetails); ok {
detailsA := a.(*rdb.EndpointPrivateNetworkDetails)
detailsB := b.(*rdb.EndpointPrivateNetworkDetails)
return reflect.DeepEqual(detailsA, detailsB)
}
}
return false
}

func flattenPrivateNetwork(endpoints []*rdb.Endpoint) (interface{}, bool) {
pnI := []map[string]interface{}(nil)
for _, endpoint := range endpoints {
Expand Down
132 changes: 0 additions & 132 deletions scaleway/helpers_rdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,142 +2,10 @@ package scaleway

import (
"context"
"net"
"reflect"
"testing"

"github.com/scaleway/scaleway-sdk-go/api/rdb/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/stretchr/testify/assert"
)

func TestIsEndPointEqual(t *testing.T) {
tests := []struct {
name string
A *rdb.EndpointPrivateNetworkDetails
B *rdb.EndpointPrivateNetworkDetails
expected bool
}{
{
name: "isEqualPrivateNetworkDetails",
A: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar1},
B: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar1},
expected: true,
},
{
name: "notEqualIP",
A: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar1},
B: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 2), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar1},
expected: false,
},
{
name: "notEqualZone",
A: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar1},
B: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar2},
expected: false,
},
{
name: "notEqualMask",
A: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(25, 32),
}}, Zone: scw.ZoneFrPar1},
B: &rdb.EndpointPrivateNetworkDetails{PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}}, Zone: scw.ZoneFrPar1},
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, isEndPointEqual(tt.A, tt.B))
})
}
}

func TestEndpointsToRemove(t *testing.T) {
tests := []struct {
name string
Endpoints []*rdb.Endpoint
Updates []interface{}
Expected map[string]bool
}{
{
name: "removeAll",
Endpoints: []*rdb.Endpoint{{
ID: "6ba7b810-9dad-11d1-80b4-00c04fd430c1",
PrivateNetwork: &rdb.EndpointPrivateNetworkDetails{
PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}},
Zone: scw.ZoneFrPar1,
},
}},
Expected: map[string]bool{
"6ba7b810-9dad-11d1-80b4-00c04fd430c1": true,
},
},
{
name: "shouldUpdatePrivateNetwork",
Endpoints: []*rdb.Endpoint{{
ID: "6ba7b810-9dad-11d1-80b4-00c04fd430c1",
PrivateNetwork: &rdb.EndpointPrivateNetworkDetails{
PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}},
Zone: scw.ZoneFrPar1,
},
}},
Updates: []interface{}{map[string]interface{}{"pn_id": "fr-par-1/6ba7b810-9dad-11d1-80b4-00c04fd430c8", "ip_net": "192.168.1.43/24"}},
Expected: map[string]bool{
"6ba7b810-9dad-11d1-80b4-00c04fd430c1": true,
},
},
{
name: "shouldNotUpdatePrivateNetwork",
Endpoints: []*rdb.Endpoint{{
ID: "6ba7b810-9dad-11d1-80b4-00c04fd430c1",
PrivateNetwork: &rdb.EndpointPrivateNetworkDetails{
PrivateNetworkID: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
ServiceIP: scw.IPNet{IPNet: net.IPNet{
IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32),
}},
Zone: scw.ZoneFrPar1,
},
}},
Updates: []interface{}{map[string]interface{}{"pn_id": "fr-par-1/6ba7b810-9dad-11d1-80b4-00c04fd430c8", "ip_net": "1.1.1.1/24"}},
Expected: map[string]bool{
"6ba7b810-9dad-11d1-80b4-00c04fd430c1": false,
},
},
{
name: "shouldAddPrivateNetwork",
Updates: []interface{}{map[string]interface{}{"pn_id": "fr-par-1/6ba7b810-9dad-11d1-80b4-00c04fd430c8", "ip_net": "1.1.1.1/24"}},
Expected: map[string]bool{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := endpointsToRemove(tt.Endpoints, tt.Updates)
assert.NoError(t, err)
assert.Equal(t, tt.Expected, result)
})
}
}

func TestRDBPrivilegeV1SchemaUpgradeFunc(t *testing.T) {
v0Schema := map[string]interface{}{
"id": "fr-par/11111111-1111-1111-1111-111111111111",
Expand Down
11 changes: 3 additions & 8 deletions scaleway/resource_rdb_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,16 +611,11 @@ func resourceScalewayRdbInstanceUpdate(ctx context.Context, d *schema.ResourceDa
return diag.FromErr(err)
}

// get endpoints to detach. It will handle only private networks
endPointsToRemove, err := endpointsToRemove(res.Endpoints, d.Get("private_network"))
if err != nil {
diag.FromErr(err)
}
for endPointID, remove := range endPointsToRemove {
if remove {
for _, e := range res.Endpoints {
if e.PrivateNetwork != nil {
err := rdbAPI.DeleteEndpoint(
&rdb.DeleteEndpointRequest{
EndpointID: endPointID, Region: region,
EndpointID: e.ID, Region: region,
},
scw.WithContext(ctx))
if err != nil {
Expand Down
82 changes: 82 additions & 0 deletions scaleway/resource_rdb_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,88 @@ func TestAccScalewayRdbInstance_PrivateNetwork(t *testing.T) {
})
}

func TestAccScalewayRdbInstance_PrivateNetworkUpdate(t *testing.T) {
tt := NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: tt.ProviderFactories,
CheckDestroy: testAccCheckScalewayRdbInstanceDestroy(tt),
Steps: []resource.TestStep{
{
Config: `
resource scaleway_vpc_private_network pn01 {
name = "my_private_network"
}
`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("scaleway_vpc_private_network.pn01", "name", "my_private_network"),
),
},
{
Config: `
resource scaleway_vpc_private_network pn01 {
name = "my_private_network"
}
resource scaleway_rdb_instance main {
name = "test-rdb"
node_type = "db-dev-s"
engine = "PostgreSQL-11"
is_ha_cluster = false
disable_backup = true
user_name = "my_initial_user"
password = "thiZ_is_v&ry_s3cret"
tags = [ "terraform-test", "scaleway_rdb_instance", "volume", "rdb_pn" ]
volume_type = "bssd"
volume_size_in_gb = 10
private_network {
pn_id = "${scaleway_vpc_private_network.pn01.id}"
}
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayRdbExists(tt, "scaleway_rdb_instance.main"),
resource.TestCheckResourceAttr("scaleway_rdb_instance.main", "private_network.#", "1"),
),
},
{
Config: `
resource scaleway_vpc_private_network pn01 {
name = "my_private_network"
}
locals {
ip_address = cidrhost(scaleway_vpc_private_network.pn01.ipv4_subnet.0.subnet, 4)
cidr_prefix = split("/", scaleway_vpc_private_network.pn01.ipv4_subnet.0.subnet)[1]
}
resource scaleway_rdb_instance main {
name = "test-rdb"
node_type = "db-dev-s"
engine = "PostgreSQL-11"
is_ha_cluster = false
disable_backup = true
user_name = "my_initial_user"
password = "thiZ_is_v&ry_s3cret"
tags = [ "terraform-test", "scaleway_rdb_instance", "volume", "rdb_pn" ]
volume_type = "bssd"
volume_size_in_gb = 10
private_network {
ip_net = format("%s/%s", local.ip_address, local.cidr_prefix)
pn_id = scaleway_vpc_private_network.pn01.id
}
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayRdbExists(tt, "scaleway_rdb_instance.main"),
resource.TestCheckResourceAttr("scaleway_rdb_instance.main", "private_network.#", "1"),
),
},
},
})
}

func TestAccScalewayRdbInstance_PrivateNetwork_DHCP(t *testing.T) {
tt := NewTestTools(t)
defer tt.Cleanup()
Expand Down
Loading