Skip to content

Commit

Permalink
Network peering translation layer
Browse files Browse the repository at this point in the history
Including fuzzing based conversion testing
  • Loading branch information
josvazg committed Oct 23, 2024
1 parent 8e7ae4d commit 78de4b3
Show file tree
Hide file tree
Showing 4 changed files with 376 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/gofuzz v1.2.0
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
Expand Down
125 changes: 125 additions & 0 deletions internal/translation/networkpeering/conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package networkpeering

import (
"fmt"

"go.mongodb.org/atlas-sdk/v20231115008/admin"

"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer"
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/provider"
)

type ProviderContainer struct {
ID string
ProviderName provider.ProviderName
AtlasCIDRBlock string
RegionName string // AWS
Region string // Azure
}

func toAtlasConnection(peer *akov2.NetworkPeer) *admin.BaseNetworkPeeringConnectionSettings {
switch peer.ProviderName {
case provider.ProviderAWS:
return &admin.BaseNetworkPeeringConnectionSettings{
ContainerId: peer.ContainerID,
ProviderName: pointer.SetOrNil(string(peer.ProviderName), ""),
AccepterRegionName: pointer.SetOrNil(peer.AccepterRegionName, ""),
AwsAccountId: pointer.SetOrNil(peer.AWSAccountID, ""),
RouteTableCidrBlock: pointer.SetOrNil(peer.RouteTableCIDRBlock, ""),
VpcId: pointer.SetOrNil(peer.VpcID, ""),
}
case provider.ProviderGCP:
return &admin.BaseNetworkPeeringConnectionSettings{
ContainerId: peer.ContainerID,
ProviderName: pointer.SetOrNil(string(peer.ProviderName), ""),
GcpProjectId: pointer.SetOrNil(peer.GCPProjectID, ""),
NetworkName: pointer.SetOrNil(peer.NetworkName, ""),
}
case provider.ProviderAzure:
return &admin.BaseNetworkPeeringConnectionSettings{
ContainerId: peer.ContainerID,
ProviderName: pointer.SetOrNil(string(peer.ProviderName), ""),
AzureDirectoryId: pointer.SetOrNil(peer.AzureDirectoryID, ""),
AzureSubscriptionId: pointer.SetOrNil(peer.AzureSubscriptionID, ""),
ResourceGroupName: pointer.SetOrNil(peer.ResourceGroupName, ""),
VnetName: pointer.SetOrNil(peer.VNetName, ""),
}
default:
panic(fmt.Errorf("unsupported provider %q", peer.ProviderName))
}
}

func fromAtlasConnection(conn *admin.BaseNetworkPeeringConnectionSettings) *akov2.NetworkPeer {
switch provider.ProviderName(conn.GetProviderName()) {
case provider.ProviderAWS:
return &akov2.NetworkPeer{
ContainerID: conn.GetContainerId(),
ProviderName: provider.ProviderName(conn.GetProviderName()),
AccepterRegionName: conn.GetAccepterRegionName(),
AWSAccountID: conn.GetAwsAccountId(),
RouteTableCIDRBlock: conn.GetRouteTableCidrBlock(),
VpcID: conn.GetVpcId(),
}
case provider.ProviderGCP:
return &akov2.NetworkPeer{
ContainerID: conn.GetContainerId(),
ProviderName: provider.ProviderName(conn.GetProviderName()),
GCPProjectID: conn.GetGcpProjectId(),
NetworkName: conn.GetNetworkName(),
}
case provider.ProviderAzure:
return &akov2.NetworkPeer{
ContainerID: conn.GetContainerId(),
ProviderName: provider.ProviderName(conn.GetProviderName()),
AzureDirectoryID: conn.GetAzureDirectoryId(),
AzureSubscriptionID: conn.GetAzureSubscriptionId(),
ResourceGroupName: conn.GetResourceGroupName(),
VNetName: conn.GetVnetName(),
}
default:
panic(fmt.Errorf("unsupported provider %q", conn.GetProviderName()))
}
}

func fromAtlasConnectionList(list []admin.BaseNetworkPeeringConnectionSettings) []akov2.NetworkPeer {
if list == nil {
return nil
}
peers := make([]akov2.NetworkPeer, 0, len(list))
for _, conn := range list {
peers = append(peers, *fromAtlasConnection(&conn))
}
return peers
}

func toAtlasContainer(container *ProviderContainer) *admin.CloudProviderContainer {
return &admin.CloudProviderContainer{
Id: pointer.SetOrNil(container.ID, ""),
ProviderName: pointer.SetOrNil(string(container.ProviderName), ""),
AtlasCidrBlock: pointer.SetOrNil(container.AtlasCIDRBlock, ""),
RegionName: pointer.SetOrNil(container.RegionName, ""),
Region: pointer.SetOrNil(container.Region, ""),
}
}

func fromAtlasContainer(container *admin.CloudProviderContainer) *ProviderContainer {
return &ProviderContainer{
ID: container.GetId(),
ProviderName: provider.ProviderName(container.GetProviderName()),
AtlasCIDRBlock: container.GetAtlasCidrBlock(),
RegionName: container.GetRegionName(),
Region: container.GetRegion(),
}
}

func fromAtlasContainerList(list []admin.CloudProviderContainer) []ProviderContainer {
if list == nil {
return nil
}
containers := make([]ProviderContainer, 0, len(list))
for _, container := range list {
containers = append(containers, *fromAtlasContainer(&container))
}
return containers
}
120 changes: 120 additions & 0 deletions internal/translation/networkpeering/conversion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package networkpeering

import (
"fmt"
"testing"

gofuzz "github.com/google/gofuzz"
"github.com/stretchr/testify/assert"
"go.mongodb.org/atlas-sdk/v20231115008/admin"

akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/provider"
)

const fuzzIterations = 100

var providerNames = []provider.ProviderName{
provider.ProviderAWS,
provider.ProviderAzure,
provider.ProviderGCP,
}

func FuzzConvertConnection(f *testing.F) {
for i := 0; i < fuzzIterations; i++ {
f.Add(([]byte)(fmt.Sprintf("seed sample %x", i)), i)
}
f.Fuzz(func(t *testing.T, data []byte, index int) {
peerData := akov2.NetworkPeer{}
gofuzz.NewFromGoFuzz(data).Fuzz(&peerData)
peerData.ProviderName = providerNames[index%3]
cleanupPeer(&peerData)
result := fromAtlasConnection(toAtlasConnection(&peerData))
assert.Equal(t, &peerData, result, "failed for index=%d", index)
})
}

func FuzzConvertConnectionList(f *testing.F) {
for i := 0; i < fuzzIterations; i++ {
f.Add(([]byte)(fmt.Sprintf("seed sample %x", i)), i, (i%5)-1)
}
f.Fuzz(func(t *testing.T, data []byte, index int, size int) {
conns := []admin.BaseNetworkPeeringConnectionSettings{}
expected := []akov2.NetworkPeer{}
if size < 0 {
conns = nil
expected = nil
} else {
for i := 0; i < size; i++ {
peerData := akov2.NetworkPeer{}
gofuzz.NewFromGoFuzz(data).Fuzz(&peerData)
peerData.ProviderName = providerNames[index%3]
cleanupPeer(&peerData)
expectedConn := fromAtlasConnection(toAtlasConnection(&peerData))
expected = append(expected, *expectedConn)
conns = append(conns, *toAtlasConnection(&peerData))
}
}
result := fromAtlasConnectionList(conns)
assert.Equal(t, expected, result)
})
}

func FuzzConvertContainer(f *testing.F) {
for i := 0; i < fuzzIterations; i++ {
f.Add(([]byte)(fmt.Sprintf("seed sample %x", i)), i)
}
f.Fuzz(func(t *testing.T, data []byte, index int) {
containerData := ProviderContainer{}
gofuzz.NewFromGoFuzz(data).Fuzz(&containerData)
containerData.ProviderName = providerNames[index%3]
result := fromAtlasContainer(toAtlasContainer(&containerData))
assert.Equal(t, &containerData, result, "failed for index=%d", index)
})
}

func FuzzConvertContainerList(f *testing.F) {
for i := 0; i < fuzzIterations; i++ {
f.Add(([]byte)(fmt.Sprintf("seed sample %x", i)), i, (i%5)-1)
}
f.Fuzz(func(t *testing.T, data []byte, index int, size int) {
containers := []admin.CloudProviderContainer{}
expected := []ProviderContainer{}
if size < 0 {
containers = nil
expected = nil
} else {
for i := 0; i < size; i++ {
containerData := ProviderContainer{}
gofuzz.NewFromGoFuzz(data).Fuzz(&containerData)
containerData.ProviderName = providerNames[index%3]
expectedContainer := fromAtlasContainer(toAtlasContainer(&containerData))
expected = append(expected, *expectedContainer)
containers = append(containers, *toAtlasContainer(&containerData))
}
}
result := fromAtlasContainerList(containers)
assert.Equal(t, expected, result)
})
}

func cleanupPeer(peer *akov2.NetworkPeer) {
peer.ContainerRegion = ""
peer.AtlasCIDRBlock = ""
if peer.ProviderName != provider.ProviderAWS {
peer.AccepterRegionName = ""
peer.AWSAccountID = ""
peer.RouteTableCIDRBlock = ""
peer.VpcID = ""
}
if peer.ProviderName != provider.ProviderGCP {
peer.GCPProjectID = ""
peer.NetworkName = ""
}
if peer.ProviderName != provider.ProviderAzure {
peer.AzureDirectoryID = ""
peer.AzureSubscriptionID = ""
peer.ResourceGroupName = ""
peer.VNetName = ""
}
}
130 changes: 130 additions & 0 deletions internal/translation/networkpeering/networkpeering.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package networkpeering

import (
"context"
"fmt"

"go.mongodb.org/atlas-sdk/v20231115008/admin"

"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer"
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/provider"
)

type PeerConnectionsService interface {
CreatePeer(ctx context.Context, projectID string, conn *akov2.NetworkPeer) (*akov2.NetworkPeer, error)
ListPeers(ctx context.Context, projectID string) ([]akov2.NetworkPeer, error)
DeletePeer(ctx context.Context, projectID, containerID string) error
}

type PeeringContainerService interface {
CreateContainer(ctx context.Context, projectID string, container *ProviderContainer) (*ProviderContainer, error)
GetContainer(ctx context.Context, projectID, containerID string) (*ProviderContainer, error)
ListContainers(ctx context.Context, projectID, providerName string) ([]ProviderContainer, error)
DeleteContainers(ctx context.Context, projectID, containerID string) error
}

type NetworkPeeringService interface {
PeerConnectionsService
PeeringContainerService
}

type NetworkPeering struct {
connsService admin.NetworkPeeringApi
containersService admin.NetworkPeeringApi
}

func (np *NetworkPeering) CreatePeer(ctx context.Context, projectID string, conn *akov2.NetworkPeer) (*akov2.NetworkPeer, error) {
newConn, _, err := np.connsService.CreatePeeringConnection(ctx, projectID, toAtlasConnection(conn)).Execute()
if err != nil {
return nil, fmt.Errorf("failed to create network peer %v: %w", conn, err)
}
return fromAtlasConnection(newConn), nil
}

func (np *NetworkPeering) ListPeers(ctx context.Context, projectID string) ([]akov2.NetworkPeer, error) {
var peersList []akov2.NetworkPeer
providers := []provider.ProviderName{provider.ProviderAWS, provider.ProviderAzure, provider.ProviderGCP}
for _, providerName := range providers {
peers, err := np.listPeersForProvider(ctx, projectID, providerName)
if err != nil {
return nil, fmt.Errorf("failed to list network peers for %s: %w", string(providerName), err)
}
peersList = append(peersList, peers...)
}
return peersList, nil
}

func (np *NetworkPeering) listPeersForProvider(ctx context.Context, projectID string, providerName provider.ProviderName) ([]akov2.NetworkPeer, error) {
results := []akov2.NetworkPeer{}
pageNum := 1
listOpts := &admin.ListPeeringConnectionsApiParams{
GroupId: projectID,
ProviderName: admin.PtrString(string(providerName)),
PageNum: pointer.MakePtr(pageNum),
}
for {
page, _, err := np.connsService.ListPeeringConnectionsWithParams(ctx, listOpts).Execute()
if err != nil {
return nil, fmt.Errorf("failed to list network peers: %w", err)
}
results = append(results, fromAtlasConnectionList(page.GetResults())...)
if len(results) >= page.GetTotalCount() {
return results, nil
}
pageNum += 1
}
}

func (np *NetworkPeering) DeletePeer(ctx context.Context, projectID, containerID string) error {
_, _, err := np.connsService.DeletePeeringConnection(ctx, projectID, containerID).Execute()
if err != nil {
return fmt.Errorf("failed to delete peering connection for container %s: %w", containerID, err)
}
return nil
}

func (np *NetworkPeering) CreateContainer(ctx context.Context, projectID string, container *ProviderContainer) (*ProviderContainer, error) {
newContainer, _, err := np.containersService.CreatePeeringContainer(ctx, projectID, toAtlasContainer(container)).Execute()
if err != nil {
return nil, fmt.Errorf("failed to create peering container %s: %w", container.ID, err)
}
return fromAtlasContainer(newContainer), nil
}

func (np *NetworkPeering) GetContainer(ctx context.Context, projectID, containerID string) (*ProviderContainer, error) {
container, _, err := np.containersService.GetPeeringContainer(ctx, projectID, containerID).Execute()
if err != nil {
return nil, fmt.Errorf("failed to get container for gcp status %s: %w", containerID, err)
}
return fromAtlasContainer(container), nil
}

func (np *NetworkPeering) ListContainers(ctx context.Context, projectID, providerName string) ([]ProviderContainer, error) {
results := []ProviderContainer{}
pageNum := 1
listOpts := &admin.ListPeeringContainerByCloudProviderApiParams{
GroupId: projectID,
ProviderName: pointer.SetOrNil(providerName, ""),
PageNum: pointer.MakePtr(pageNum),
}
for {
page, _, err := np.containersService.ListPeeringContainerByCloudProviderWithParams(ctx, listOpts).Execute()
if err != nil {
return nil, fmt.Errorf("failed to list containers: %w", err)
}
results = append(results, fromAtlasContainerList(page.GetResults())...)
if len(results) >= page.GetTotalCount() {
return results, nil
}
pageNum += 1
}
}

func (np *NetworkPeering) DeleteContainers(ctx context.Context, projectID, containerID string) error {
_, _, err := np.connsService.DeletePeeringContainer(ctx, projectID, containerID).Execute()
if err != nil {
return fmt.Errorf("failed to delete container: %w", err)
}
return nil
}

0 comments on commit 78de4b3

Please sign in to comment.