Skip to content

Commit

Permalink
Add support for Shared VPC Networking
Browse files Browse the repository at this point in the history
This is an update to the stale PR #991

** Added support for Host Project for a shared VPC in the Network struct.
** Network Resources will now use the host project name if exists, otherwise the normal project.
** Update the cluster getter interface to include the NetworkProject and Indicator for a shared VPC.
** Update reconcilers for girewall rules, subnets and network.
** Update the services to use the host project for resources when a shared vpc is used.
  • Loading branch information
barbacbd committed Mar 22, 2024
1 parent f6c2c4f commit 2b06e8c
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 7 deletions.
4 changes: 4 additions & 0 deletions api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ type NetworkSpec struct {
// Allow for configuration of load balancer backend (useful for changing apiserver port)
// +optional
LoadBalancerBackendPort *int32 `json:"loadBalancerBackendPort,omitempty"`

// HostProject is the name of the host project hosting the shared VPC network resources.
// +optional
HostProject *string `json:"hostProject,omitempty"`
}

// SubnetSpec configures an GCP Subnet.
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions cloud/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type ReconcilerWithResult interface {
// Client is an interface which can get cloud client.
type Client interface {
Cloud() Cloud
NetworkCloud() Cloud
}

// ClusterGetter is an interface which can get cluster information.
Expand All @@ -56,6 +57,8 @@ type ClusterGetter interface {
Name() string
Namespace() string
NetworkName() string
NetworkProject() string
IsSharedVpc() bool
Network() *infrav1.Network
AdditionalLabels() infrav1.Labels
FailureDomains() clusterv1.FailureDomains
Expand Down
18 changes: 17 additions & 1 deletion cloud/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,27 @@ func (s *ClusterScope) Cloud() cloud.Cloud {
return newCloud(s.Project(), s.GCPServices)
}

// NetworkCloud returns initialized cloud.
func (s *ClusterScope) NetworkCloud() cloud.Cloud {
return newCloud(s.NetworkProject(), s.GCPServices)
}

// Project returns the current project name.
func (s *ClusterScope) Project() string {
return s.GCPCluster.Spec.Project
}

// NetworkProject returns the project name where network resources should exist.
// The network project defaults to the Project when one is not supplied.
func (s *ClusterScope) NetworkProject() string {
return ptr.Deref(s.GCPCluster.Spec.Network.HostProject, s.Project())
}

// IsSharedVpc returns true If sharedVPC used else , returns false.
func (s *ClusterScope) IsSharedVpc() bool {
return s.NetworkProject() != s.Project()
}

// Region returns the cluster region.
func (s *ClusterScope) Region() string {
return s.GCPCluster.Spec.Region
Expand All @@ -117,7 +133,7 @@ func (s *ClusterScope) NetworkName() string {

// NetworkLink returns the partial URL for the network.
func (s *ClusterScope) NetworkLink() string {
return fmt.Sprintf("projects/%s/global/networks/%s", s.Project(), s.NetworkName())
return fmt.Sprintf("projects/%s/global/networks/%s", s.NetworkProject(), s.NetworkName())
}

// Network returns the cluster network object.
Expand Down
9 changes: 7 additions & 2 deletions cloud/scope/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ func (m *MachineScope) Cloud() cloud.Cloud {
return m.ClusterGetter.Cloud()
}

// NetworkCloud returns initialized network cloud.
func (m *MachineScope) NetworkCloud() cloud.Cloud {
return m.ClusterGetter.NetworkCloud()
}

// Zone returns the FailureDomain for the GCPMachine.
func (m *MachineScope) Zone() string {
if m.Machine.Spec.FailureDomain == nil {
Expand Down Expand Up @@ -318,7 +323,7 @@ func (m *MachineScope) InstanceAdditionalDiskSpec() []*compute.AttachedDisk {
// InstanceNetworkInterfaceSpec returns compute network interface spec.
func (m *MachineScope) InstanceNetworkInterfaceSpec() *compute.NetworkInterface {
networkInterface := &compute.NetworkInterface{
Network: path.Join("projects", m.ClusterGetter.Project(), "global", "networks", m.ClusterGetter.NetworkName()),
Network: path.Join("projects", m.ClusterGetter.NetworkProject(), "global", "networks", m.ClusterGetter.NetworkName()),
}

if m.GCPMachine.Spec.PublicIP != nil && *m.GCPMachine.Spec.PublicIP {
Expand All @@ -331,7 +336,7 @@ func (m *MachineScope) InstanceNetworkInterfaceSpec() *compute.NetworkInterface
}

if m.GCPMachine.Spec.Subnet != nil {
networkInterface.Subnetwork = path.Join("regions", m.ClusterGetter.Region(), "subnetworks", *m.GCPMachine.Spec.Subnet)
networkInterface.Subnetwork = path.Join("projects", m.ClusterGetter.NetworkProject(), "regions", m.ClusterGetter.Region(), "subnetworks", *m.GCPMachine.Spec.Subnet)
}

return networkInterface
Expand Down
18 changes: 17 additions & 1 deletion cloud/scope/managedcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ func (s *ManagedClusterScope) Cloud() cloud.Cloud {
return newCloud(s.Project(), s.GCPServices)
}

// NetworkCloud returns initialized cloud.
func (s *ManagedClusterScope) NetworkCloud() cloud.Cloud {
return newCloud(s.NetworkProject(), s.GCPServices)
}

// Project returns the current project name.
func (s *ManagedClusterScope) Project() string {
return s.GCPManagedCluster.Spec.Project
Expand All @@ -118,9 +123,20 @@ func (s *ManagedClusterScope) NetworkName() string {
return ptr.Deref(s.GCPManagedCluster.Spec.Network.Name, "default")
}

// NetworkProject returns the project name where network resources should exist.
// The network project defaults to the Project when one is not supplied.
func (s *ManagedClusterScope) NetworkProject() string {
return ptr.Deref(s.GCPManagedCluster.Spec.Network.HostProject, s.Project())
}

// IsSharedVpc returns true If sharedVPC used else , returns false.
func (s *ManagedClusterScope) IsSharedVpc() bool {
return s.NetworkProject() != s.Project()
}

// NetworkLink returns the partial URL for the network.
func (s *ManagedClusterScope) NetworkLink() string {
return fmt.Sprintf("projects/%s/global/networks/%s", s.Project(), s.NetworkName())
return fmt.Sprintf("projects/%s/global/networks/%s", s.NetworkProject(), s.NetworkName())
}

// Network returns the cluster network object.
Expand Down
8 changes: 8 additions & 0 deletions cloud/services/compute/firewalls/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ import (
// Reconcile reconcile cluster firewall compoenents.
func (s *Service) Reconcile(ctx context.Context) error {
log := log.FromContext(ctx)
if s.scope.IsSharedVpc() {
log.Info("VPC enabled. Ignore Reconciling firewall resources")
return nil
}
log.Info("Reconciling firewall resources")
for _, spec := range s.scope.FirewallRulesSpec() {
log.V(2).Info("Looking firewall", "name", spec.Name)
Expand All @@ -49,6 +53,10 @@ func (s *Service) Reconcile(ctx context.Context) error {
// Delete delete cluster firewall compoenents.
func (s *Service) Delete(ctx context.Context) error {
log := log.FromContext(ctx)
if s.scope.IsSharedVpc() {
log.Info("VPC enabled. Ignore Deleting firewall resources")
return nil
}
log.Info("Deleting firewall resources")
for _, spec := range s.scope.FirewallRulesSpec() {
log.V(2).Info("Deleting firewall", "name", spec.Name)
Expand Down
11 changes: 11 additions & 0 deletions cloud/services/compute/networks/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func (s *Service) Reconcile(ctx context.Context) error {
// Delete delete cluster network components.
func (s *Service) Delete(ctx context.Context) error {
log := log.FromContext(ctx)
if s.scope.IsSharedVpc() {
log.Info("VPC enabled. Ignore Deleting network resources")
s.scope.Network().Router = nil
s.scope.Network().SelfLink = nil
return nil
}
log.Info("Deleting network resources")
networkKey := meta.GlobalKey(s.scope.NetworkName())
log.V(2).Info("Looking for network before deleting", "name", networkKey)
Expand Down Expand Up @@ -102,6 +108,11 @@ func (s *Service) createOrGetNetwork(ctx context.Context) (*compute.Network, err
return nil, err
}

if s.scope.IsSharedVpc() {
log.Error(err, "VPC is enabled. Error looking for network", "name", s.scope.NetworkName())
return nil, err
}

log.V(2).Info("Creating a network", "name", s.scope.NetworkName())
if err := s.networks.Insert(ctx, networkKey, s.scope.NetworkSpec()); err != nil {
log.Error(err, "Error creating a network", "name", s.scope.NetworkName())
Expand Down
9 changes: 7 additions & 2 deletions cloud/services/compute/networks/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ var _ cloud.Reconciler = &Service{}

// New returns Service from given scope.
func New(scope Scope) *Service {
scopeCloud := scope.Cloud()
if scope.IsSharedVpc() {
scopeCloud = scope.NetworkCloud()
}

return &Service{
scope: scope,
networks: scope.Cloud().Networks(),
routers: scope.Cloud().Routers(),
networks: scopeCloud.Networks(),
routers: scopeCloud.Routers(),
}
}
9 changes: 9 additions & 0 deletions cloud/services/compute/subnets/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func (s *Service) Reconcile(ctx context.Context) error {
// Delete deletes cluster subnetwork components.
func (s *Service) Delete(ctx context.Context) error {
logger := log.FromContext(ctx)
if s.scope.IsSharedVpc() {
logger.Info("VPC enabled. Ignore Deleting subnet resources")
return nil
}
for _, subnetSpec := range s.scope.SubnetSpecs() {
logger.V(2).Info("Deleting a subnet", "name", subnetSpec.Name)
subnetKey := meta.RegionalKey(subnetSpec.Name, s.scope.Region())
Expand Down Expand Up @@ -68,6 +72,11 @@ func (s *Service) createOrGetSubnets(ctx context.Context) ([]*compute.Subnetwork
return subnets, err
}

if s.scope.IsSharedVpc() {
logger.Error(err, "VPC is enabled. Error looking for subnetwork", "name", subnetSpec.Name)
return nil, err
}

// Subnet was not found, let's create it
logger.V(2).Info("Creating a subnet", "name", subnetSpec.Name)
if err := s.subnets.Insert(ctx, subnetKey, subnetSpec); err != nil {
Expand Down
7 changes: 6 additions & 1 deletion cloud/services/compute/subnets/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ var _ cloud.Reconciler = &Service{}

// New returns Service from given scope.
func New(scope Scope) *Service {
cloudScope := scope.Cloud()
if scope.IsSharedVpc() {
cloudScope = scope.NetworkCloud()
}

return &Service{
scope: scope,
subnets: scope.Cloud().Subnetworks(),
subnets: cloudScope.Subnetworks(),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ spec:
predetermined range as described in Auto mode VPC network IP
ranges. \n Defaults to true."
type: boolean
hostProject:
description: HostProject is the name of the host project hosting
the shared VPC network resources.
type: string
loadBalancerBackendPort:
description: Allow for configuration of load balancer backend
(useful for changing apiserver port)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ spec:
region. Each subnet has a predetermined range as described
in Auto mode VPC network IP ranges. \n Defaults to true."
type: boolean
hostProject:
description: HostProject is the name of the host project
hosting the shared VPC network resources.
type: string
loadBalancerBackendPort:
description: Allow for configuration of load balancer
backend (useful for changing apiserver port)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ spec:
predetermined range as described in Auto mode VPC network IP
ranges. \n Defaults to true."
type: boolean
hostProject:
description: HostProject is the name of the host project hosting
the shared VPC network resources.
type: string
loadBalancerBackendPort:
description: Allow for configuration of load balancer backend
(useful for changing apiserver port)
Expand Down

0 comments on commit 2b06e8c

Please sign in to comment.