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 kubernetes-sigs#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 Apr 12, 2024
1 parent f6c2c4f commit 6da86fb
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 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.V(2).Info("Shared 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.V(2).Info("Shared 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.V(2).Info("Shared 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.V(2).Info("Shared 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 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 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 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 6da86fb

Please sign in to comment.