Skip to content

Commit

Permalink
feat(GCPVpcPeering) Delete VPC Peering
Browse files Browse the repository at this point in the history
  • Loading branch information
bru-jer-work committed Jul 30, 2024
1 parent 4ee1913 commit b394223
Show file tree
Hide file tree
Showing 17 changed files with 258 additions and 37 deletions.
2 changes: 1 addition & 1 deletion internal/controller/cloud-control/vpcpeering_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func SetupVpcPeeringReconciler(
kcpManager manager.Manager,
awsSkrProvider awsclient.SkrClientProvider[awsvpcpeeringclient.Client],
azureSkrProvider azureclient.SkrClientProvider[azurevpcpeeringclient.Client],
gcpSkrProvider gcpclient.ClientProvider[gcpvpcpeeringclient.Client],
gcpSkrProvider gcpclient.ClientProvider[gcpvpcpeeringclient.VpcPeeringClient],
env abstractions.Environment,
) error {
if env == nil {
Expand Down
14 changes: 14 additions & 0 deletions internal/controller/cloud-control/vpcpeering_gcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
. "github.com/kyma-project/cloud-manager/pkg/testinfra/dsl"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"time"
)

var _ = Describe("Feature: KCP VpcPeering", func() {
Expand Down Expand Up @@ -54,5 +55,18 @@ var _ = Describe("Feature: KCP VpcPeering", func() {
Should(Succeed())
})

// DELETE
By("When KCP VpcPeering is deleted", func() {
Eventually(Delete).
WithArguments(infra.Ctx(), infra.KCP().Client(), vpcpeering).
Should(Succeed(), "deleting VpcPeering failed")
})

By("Then VpcPeering does not exist", func() {
Eventually(IsDeleted, 5*time.Second).
WithArguments(infra.Ctx(), infra.KCP().Client(), vpcpeering).
Should(Succeed(), "expected VpcPeering does not to exist (being deleted), but it still exists")
})

})
})
4 changes: 2 additions & 2 deletions pkg/kcp/provider/gcp/mock/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ func (s *server) FileBackupClientProvider() client.ClientProvider[backupclient.F
}
}

func (s *server) VpcPeeringSkrProvider() cloudclient.ClientProvider[gcpvpccpeering.Client] {
return func(ctx context.Context, saJsonKeyPath string) (gcpvpccpeering.Client, error) {
func (s *server) VpcPeeringSkrProvider() cloudclient.ClientProvider[gcpvpccpeering.VpcPeeringClient] {
return func(ctx context.Context, saJsonKeyPath string) (gcpvpccpeering.VpcPeeringClient, error) {
logger := composed.LoggerFromCtx(ctx)
logger.Info("Inside the GCP VPCPeeringProvider mock...")
return s, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/kcp/provider/gcp/mock/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Providers interface {
ServiceUsageClientProvider() client.ClientProvider[client.ServiceUsageClient]
FilerestoreClientProvider() client.ClientProvider[restoreclient.FileRestoreClient]
FileBackupClientProvider() client.ClientProvider[backupclient.FileBackupClient]
VpcPeeringSkrProvider() cloudclient.ClientProvider[gcpvpcpeeringclient.Client]
VpcPeeringSkrProvider() cloudclient.ClientProvider[gcpvpcpeeringclient.VpcPeeringClient]
MemoryStoreProviderFake() client.ClientProvider[memoryStoreClient.MemorystoreClient]
}

Expand Down
12 changes: 11 additions & 1 deletion pkg/kcp/provider/gcp/mock/vpcPeeringStore.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mock

import (
compute "cloud.google.com/go/compute/apiv1"
pb "cloud.google.com/go/compute/apiv1/computepb"
"context"
"github.com/elliotchance/pie/v2"
Expand All @@ -16,7 +17,7 @@ type vpcPeeringStore struct {
items []*vpcPeeringEntry
}

func (s *vpcPeeringStore) CreateVpcPeeringConnection(ctx context.Context, name *string, remoteVpc *string, remoteProject *string, importCustomRoutes *bool, kymaProject *string, kymaVpc *string) (*pb.NetworkPeering, error) {
func (s *vpcPeeringStore) CreateVpcPeering(ctx context.Context, name *string, remoteVpc *string, remoteProject *string, importCustomRoutes *bool, kymaProject *string, kymaVpc *string) (*pb.NetworkPeering, error) {
s.m.Lock()
defer s.m.Unlock()

Expand All @@ -34,6 +35,15 @@ func (s *vpcPeeringStore) CreateVpcPeeringConnection(ctx context.Context, name *
return item.peering, nil
}

func (s *vpcPeeringStore) DeleteVpcPeering(ctx context.Context, name *string, kymaProject *string, kymaVpc *string) (*compute.Operation, error) {
s.m.Lock()
defer s.m.Unlock()
s.items = pie.Filter(s.items, func(vpe *vpcPeeringEntry) bool {
return !(vpe.peering.Name == name && *vpe.peering.Network == "https://www.googleapis.com/compute/v1/projects/"+*kymaProject+"/global/networks/"+*kymaVpc)
})
return nil, nil
}

func (s *vpcPeeringStore) DescribeVpcPeeringConnections(ctx context.Context) ([]*pb.NetworkPeering, error) {
s.m.Lock()
defer s.m.Unlock()
Expand Down
64 changes: 44 additions & 20 deletions pkg/kcp/provider/gcp/vpcpeering/client/cloudComputeClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,42 @@ required GCP permissions
compute.networks.ListEffectiveTags => https://cloud.google.com/resource-manager/reference/rest/v3/tagKeys/get
*/

func NewClientProvider() cloudclient.ClientProvider[Client] {
return func(ctx context.Context, saJsonKeyPath string) (Client, error) {
c, err := compute.NewNetworksRESTClient(ctx, option.WithCredentialsFile(saJsonKeyPath))
if err != nil {
return nil, err
}
return &networkClient{cnc: c}, nil
func createGcpNetworksClient(ctx context.Context) (*compute.NetworksClient, error) {
c, err := compute.NewNetworksRESTClient(ctx, option.WithCredentialsFile(abstractions.NewOSEnvironment().Get("GCP_SA_JSON_KEY_PATH")))
if err != nil {
return nil, err
}
return c, nil
}

func NewClientProvider() cloudclient.ClientProvider[VpcPeeringClient] {
return func(ctx context.Context, saJsonKeyPath string) (VpcPeeringClient, error) {
return &networkClient{}, nil
}
}

type networkClient struct {
cnc *compute.NetworksClient
}

type Client interface {
CreateVpcPeeringConnection(ctx context.Context, name *string, remoteVpc *string, remoteProject *string, importCustomRoutes *bool, kymaProject *string, kymaVpc *string) (*pb.NetworkPeering, error)
type VpcPeeringClient interface {
CreateVpcPeering(ctx context.Context, name *string, remoteVpc *string, remoteProject *string, importCustomRoutes *bool, kymaProject *string, kymaVpc *string) (*pb.NetworkPeering, error)
DeleteVpcPeering(ctx context.Context, name *string, kymaProject *string, kymaVpc *string) (*compute.Operation, error)
}

func (c *networkClient) CreateVpcPeeringConnection(ctx context.Context, name *string, remoteVpc *string, remoteProject *string, importCustomRoutes *bool, kymaProject *string, kymaVpc *string) (*pb.NetworkPeering, error) {
func (c *networkClient) CreateVpcPeering(ctx context.Context, name *string, remoteVpc *string, remoteProject *string, importCustomRoutes *bool, kymaProject *string, kymaVpc *string) (*pb.NetworkPeering, error) {

kymaNetwork := getFullNetworkUrl(*kymaProject, *kymaVpc)
remoteNetwork := getFullNetworkUrl(*remoteProject, *remoteVpc)
defer c.cnc.Close()

gcpNetworkClient, err := createGcpNetworksClient(ctx)

if err != nil {
return nil, err
}
defer gcpNetworkClient.Close()

//NetworkPeering will only be created if the remote vpc has a tag with the kyma shoot name
remoteNetworkInfo, err := c.cnc.Get(ctx, &pb.GetNetworkRequest{Network: *remoteVpc, Project: *remoteProject})
remoteNetworkInfo, err := gcpNetworkClient.Get(ctx, &pb.GetNetworkRequest{Network: *remoteVpc, Project: *remoteProject})
if err != nil {
return nil, err
}
Expand All @@ -82,16 +92,13 @@ func (c *networkClient) CreateVpcPeeringConnection(ctx context.Context, name *st
},
}

_, err = c.cnc.AddPeering(ctx, peeringRequestFromKyma)
_, err = gcpNetworkClient.AddPeering(ctx, peeringRequestFromKyma)
if err != nil {
return nil, err
}

var networkPeering *pb.NetworkPeering
net, err := c.cnc.Get(ctx, &pb.GetNetworkRequest{Network: *kymaVpc, Project: *kymaProject})
if err != nil {
return nil, err
}
net, err := gcpNetworkClient.Get(ctx, &pb.GetNetworkRequest{Network: *kymaVpc, Project: *kymaProject})
nps := net.GetPeerings()
for _, np := range nps {
if *np.Network == remoteNetwork {
Expand Down Expand Up @@ -119,20 +126,37 @@ func (c *networkClient) CreateVpcPeeringConnection(ctx context.Context, name *st
},
}

_, err = c.cnc.AddPeering(ctx, peeringRequestFromRemote)
_, err = gcpNetworkClient.AddPeering(ctx, peeringRequestFromRemote)
if err != nil {
return networkPeering, err
}

return networkPeering, nil
}

func (c *networkClient) DeleteVpcPeering(ctx context.Context, name *string, kymaProject *string, kymaVpc *string) (*compute.Operation, error) {
gcpNetworkClient, err := createGcpNetworksClient(ctx)
if err != nil {
return nil, err
}
defer gcpNetworkClient.Close()
deleteVpcPeeringOperation, err := gcpNetworkClient.RemovePeering(ctx, &pb.RemovePeeringNetworkRequest{
Network: *kymaVpc,
Project: *kymaProject,
NetworksRemovePeeringRequestResource: &pb.NetworksRemovePeeringRequest{Name: name},
})
if err != nil {
return nil, err
}
return deleteVpcPeeringOperation, nil
}

func getFullNetworkUrl(project, vpc string) string {
return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/networks/%s", project, vpc)
}

func (c *networkClient) CheckRemoteNetworkTags(context context.Context, remoteNetwork *pb.Network, desiredTag string) (bool, error) {
//Unfortunately get networks doesn't have the tags, so we need to use the resource manager tag bindings client
//Unfortunately get networks doesn't return the tags, so we need to use the resource manager tag bindings client
tbc, err := resourcemanager.NewTagBindingsClient(context, option.WithCredentialsFile(abstractions.NewOSEnvironment().Get("GCP_SA_JSON_KEY_PATH")))
if err != nil {
return false, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func createVpcPeeringConnection(ctx context.Context, st composed.State) (error,
project := gcpScope.Project
vpc := gcpScope.VpcNetwork

con, err := state.client.CreateVpcPeeringConnection(
con, err := state.client.CreateVpcPeering(
ctx,
state.peeringName,
state.remoteVpc,
Expand Down
27 changes: 27 additions & 0 deletions pkg/kcp/provider/gcp/vpcpeering/deleteVpcPeering.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package vpcpeering

import (
"context"
"github.com/kyma-project/cloud-manager/pkg/composed"
)

func deleteVpcPeering(ctx context.Context, st composed.State) (error, context.Context) {
state := st.(*State)
obj := state.ObjAsVpcPeering()
logger := composed.LoggerFromCtx(ctx)

logger.Info("Deleting GCP VPC Peering " + obj.Spec.VpcPeering.Gcp.PeeringName)

_, err := state.client.DeleteVpcPeering(
ctx,
&obj.Spec.VpcPeering.Gcp.PeeringName,
&state.Scope().Spec.Scope.Gcp.Project,
&state.Scope().Spec.Scope.Gcp.VpcNetwork,
)

if err != nil {
return err, ctx
}

return nil, nil
}
12 changes: 11 additions & 1 deletion pkg/kcp/provider/gcp/vpcpeering/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,17 @@ func New(stateFactory StateFactory) composed.Action {
addFinalizer,
createVpcPeeringConnection,
updateSuccessStatus,
composed.StopAndForgetAction),
composed.StopAndForgetAction,
),
composed.NewCase(
composed.MarkedForDeletionPredicate,
composed.ComposeActions(
"gcpVpcPeering-delete",
removeReadyCondition,
deleteVpcPeering,
removeFinalizer,
),
),
), // switch
composed.StopAndForgetAction,
)(ctx, state)
Expand Down
27 changes: 27 additions & 0 deletions pkg/kcp/provider/gcp/vpcpeering/removeFinalizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package vpcpeering

import (
"context"
cloudcontrolv1beta1 "github.com/kyma-project/cloud-manager/api/cloud-control/v1beta1"
"github.com/kyma-project/cloud-manager/pkg/composed"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func removeFinalizer(ctx context.Context, st composed.State) (error, context.Context) {
state := st.(*State)
logger := composed.LoggerFromCtx(ctx)

isUpdated := controllerutil.RemoveFinalizer(state.ObjAsVpcPeering(), cloudcontrolv1beta1.FinalizerName)
if !isUpdated {
return nil, nil
}

logger.Info("Removing finalizer")

err := state.UpdateObj(ctx)
if err != nil {
return composed.LogErrorAndReturn(err, "Error updating KCP VpcPeering after finalizer removed", composed.StopWithRequeue, ctx)
}

return composed.StopAndForget, nil
}
29 changes: 29 additions & 0 deletions pkg/kcp/provider/gcp/vpcpeering/removeReadyCondition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package vpcpeering

import (
"context"

cloudcontrolv1beta1 "github.com/kyma-project/cloud-manager/api/cloud-control/v1beta1"
"github.com/kyma-project/cloud-manager/pkg/composed"
"k8s.io/apimachinery/pkg/api/meta"
)

func removeReadyCondition(ctx context.Context, st composed.State) (error, context.Context) {
state := st.(*State)
logger := composed.LoggerFromCtx(ctx)

readyCondition := meta.FindStatusCondition(*state.ObjAsVpcPeering().Conditions(), cloudcontrolv1beta1.ConditionTypeReady)
if readyCondition == nil {
return nil, nil
}

logger.Info("Removing Ready condition")

meta.RemoveStatusCondition(state.ObjAsVpcPeering().Conditions(), cloudcontrolv1beta1.ConditionTypeReady)
err := state.UpdateObjStatus(ctx)
if err != nil {
return composed.LogErrorAndReturn(err, "Error updating KCP VpcPeering status after removing Ready condition", composed.StopWithRequeue, ctx)
}

return composed.StopWithRequeue, nil
}
12 changes: 6 additions & 6 deletions pkg/kcp/provider/gcp/vpcpeering/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
type State struct {
vpcpeeringtypes.State

client vpcpeeringclient.Client
provider gcpclient.ClientProvider[vpcpeeringclient.Client]
client vpcpeeringclient.VpcPeeringClient
provider gcpclient.ClientProvider[vpcpeeringclient.VpcPeeringClient]

//gcp config
gcpConfig *gcpclient.GcpConfig
Expand All @@ -31,12 +31,12 @@ type StateFactory interface {
}

type stateFactory struct {
skrProvider gcpclient.ClientProvider[vpcpeeringclient.Client]
skrProvider gcpclient.ClientProvider[vpcpeeringclient.VpcPeeringClient]
env abstractions.Environment
gcpConfig *gcpclient.GcpConfig
}

func NewStateFactory(skrProvider gcpclient.ClientProvider[vpcpeeringclient.Client], env abstractions.Environment) StateFactory {
func NewStateFactory(skrProvider gcpclient.ClientProvider[vpcpeeringclient.VpcPeeringClient], env abstractions.Environment) StateFactory {
return &stateFactory{
skrProvider: skrProvider,
env: env,
Expand All @@ -58,8 +58,8 @@ func (f *stateFactory) NewState(ctx context.Context, vpcPeeringState vpcpeeringt
}

func newState(vpcPeeringState vpcpeeringtypes.State,
client vpcpeeringclient.Client,
provider gcpclient.ClientProvider[vpcpeeringclient.Client],
client vpcpeeringclient.VpcPeeringClient,
provider gcpclient.ClientProvider[vpcpeeringclient.VpcPeeringClient],
gcpConfig *gcpclient.GcpConfig) *State {
return &State{
State: vpcPeeringState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@ import (
"context"
cloudcontrol1beta1 "github.com/kyma-project/cloud-manager/api/cloud-control/v1beta1"
"github.com/kyma-project/cloud-manager/pkg/composed"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func updateSuccessStatus(ctx context.Context, st composed.State) (error, context.Context) {
state := st.(*State)

if meta.IsStatusConditionTrue(
*state.ObjAsVpcPeering().Conditions(),
cloudcontrol1beta1.ConditionTypeReady,
) {
return nil, nil
}

return composed.UpdateStatus(state.ObjAsVpcPeering()).
SetExclusiveConditions(metav1.Condition{
Type: cloudcontrol1beta1.ConditionTypeReady,
Expand Down
Loading

0 comments on commit b394223

Please sign in to comment.