Skip to content

Commit

Permalink
Merge pull request #307 from spectrocloud/cloudNat
Browse files Browse the repository at this point in the history
✨ Auto create Cloud NAT if network is created by CAPG
  • Loading branch information
k8s-ci-robot authored Dec 2, 2020
2 parents 6186b9e + f321e5d commit da366aa
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
5 changes: 5 additions & 0 deletions api/v1alpha3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ type Network struct {
// +optional
FirewallRules map[string]string `json:"firewallRules,omitempty"`

// Router is the full reference to the router created within the network
// it'll contain the cloud nat gateway
// +optional
Router *string `json:"router,omitempty"`

// APIServerAddress is the IPV4 global address assigned to the load balancer
// created for the API Server.
// +optional
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha3/zz_generated.deepcopy.go

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

82 changes: 82 additions & 0 deletions cloud/services/compute/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package compute

import (
"fmt"
"github.com/pkg/errors"
"google.golang.org/api/compute/v1"
"k8s.io/utils/pointer"
Expand All @@ -31,7 +32,9 @@ func (s *Service) ReconcileNetwork() error {
// Create Network
spec := s.getNetworkSpec()
network, err := s.networks.Get(s.scope.Project(), spec.Name).Do()
autoCreateCloudNat := false
if gcperrors.IsNotFound(err) {
autoCreateCloudNat = true
op, err := s.networks.Insert(s.scope.Project(), spec).Do()
if err != nil {
return errors.Wrapf(err, "failed to create network")
Expand All @@ -49,6 +52,12 @@ func (s *Service) ReconcileNetwork() error {
return errors.Wrapf(err, "failed to describe network")
}

if autoCreateCloudNat {
if err := s.createCloudNat(network); err != nil {
return errors.Wrapf(err, "failed to create cloudnat gateway")
}
}

s.scope.GCPCluster.Spec.Network.Name = pointer.StringPtr(network.Name)
s.scope.GCPCluster.Spec.Network.AutoCreateSubnetworks = pointer.BoolPtr(network.AutoCreateSubnetworks)
s.scope.GCPCluster.Status.Network.SelfLink = pointer.StringPtr(network.SelfLink)
Expand Down Expand Up @@ -81,6 +90,22 @@ func (s *Service) DeleteNetwork() error {
return nil
}

// Delete Router.
router, err := s.routers.Get(s.scope.Project(), s.scope.Region(), getRouterName(s.scope.NetworkName())).Do()
if err == nil {
op, err := s.routers.Delete(s.scope.Project(), s.scope.Region(), router.Name).Do()
if err != nil {
return errors.Wrapf(err, "failed to delete router")
}
if err := wait.ForComputeOperation(s.scope.Compute, s.scope.Project(), op); err != nil {
return errors.Wrapf(err, "failed to wait for delete router")
}
} else {
if !gcperrors.IsNotFound(err) {
return errors.Wrapf(err, "failed to get router to delete")
}
}

// Delete Network.
op, err := s.networks.Delete(s.scope.Project(), network.Name).Do()
if err != nil {
Expand All @@ -95,3 +120,60 @@ func (s *Service) DeleteNetwork() error {

return nil
}

func (s *Service) createCloudNat(network *compute.Network) error {
router, err := s.routers.Get(s.scope.Project(), s.scope.Region(), getRouterName(s.scope.NetworkName())).Do()
if gcperrors.IsNotFound(err) {
router = s.getRouterSpec(network)
op, err := s.routers.Insert(s.scope.Project(), s.scope.Region(), router).Do()
if err != nil {
return errors.Wrapf(err, "failed to create router")
}
if err := wait.ForComputeOperation(s.scope.Compute, s.scope.Project(), op); err != nil {
return errors.Wrapf(err, "failed to wait for create router operation")
}
router, err = s.routers.Get(s.scope.Project(), s.scope.Region(), router.Name).Do()
if err != nil {
return errors.Wrapf(err, "failed to get router after create")
}
} else if err != nil {
return errors.Wrapf(err, "failed to get routers")
}

if len(router.Nats) == 0 {
router.Nats = []*compute.RouterNat{s.getRouterNatSpec()}
op, err := s.routers.Patch(s.scope.Project(), s.scope.Region(), router.Name, router).Do()
if err != nil {
return errors.Wrapf(err, "failed to patch router to create nat")
}
if err := wait.ForComputeOperation(s.scope.Compute, s.scope.Project(), op); err != nil {
return errors.Wrapf(err, "failed to wait for patch router operation")
}
}

s.scope.GCPCluster.Status.Network.Router = pointer.StringPtr(router.SelfLink)
return nil
}

func (s *Service) getRouterSpec(network *compute.Network) *compute.Router {
return &compute.Router{
Name: getRouterName(network.Name),
Network: network.SelfLink,
Nats: []*compute.RouterNat{s.getRouterNatSpec()},
}
}

func (s *Service) getRouterNatSpec() *compute.RouterNat {
return &compute.RouterNat{
Name: getRouterNatName(s.scope.NetworkName()),
NatIpAllocateOption: "AUTO_ONLY",
SourceSubnetworkIpRangesToNat: "ALL_SUBNETWORKS_ALL_IP_RANGES",
}
}

func getRouterName(network string) string {
return fmt.Sprintf("%s-%s", network, "router")
}
func getRouterNatName(network string) string {
return fmt.Sprintf("%s-%s", network, "nat")
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ spec:
description: FirewallRules is a map from the name of the rule
to its full reference.
type: object
router:
description: Router is the full reference to the router created
within the network it'll contain the cloud nat gateway
type: string
selfLink:
description: SelfLink is the link to the Network used for this
cluster.
Expand Down

0 comments on commit da366aa

Please sign in to comment.