Skip to content

Commit

Permalink
Add direct controller for regional tcp proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
gemmahou committed Nov 18, 2024
1 parent e117952 commit 149e141
Show file tree
Hide file tree
Showing 17 changed files with 930 additions and 87 deletions.
62 changes: 30 additions & 32 deletions apis/compute/v1beta1/targettcpproxy_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"fmt"
"strings"

"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct"

refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -33,7 +35,8 @@ var _ refsv1beta1.ExternalNormalizer = &ComputeTargetTCPProxyRef{}
// holds the GCP identifier for the KRM object.
type ComputeTargetTCPProxyRef struct {
// A reference to an externally managed ComputeTargetTCPProxy resource.
// Should be in the format "projects/<projectID>/regions/<region>/targetTcpProxies/<targettcpproxyID>".
// Should be in the format "projects/<projectID>/global/targetTcpProxies/<targettcpproxyID>"
// or "projects/<projectID>/regions/<region>/targetTcpProxies/<targettcpproxyID>".
External string `json:"external,omitempty"`

// The name of a ComputeTargetTCPProxy resource.
Expand Down Expand Up @@ -95,7 +98,13 @@ func NewComputeTargetTCPProxyRef(ctx context.Context, reader client.Reader, obj
return nil, fmt.Errorf("cannot resolve project")
}

id.parent = &ComputeTargetTCPProxyParent{ProjectID: projectID}
// Get Region
if obj.Spec.Location == nil {
id.parent = &ComputeTargetTCPProxyParent{ProjectID: projectID, Region: "global"}
} else {
region := direct.ValueOf(obj.Spec.Location)
id.parent = &ComputeTargetTCPProxyParent{ProjectID: projectID, Region: region}
}

// Get desired ID
resourceID := valueOf(obj.Spec.ResourceID)
Expand Down Expand Up @@ -127,7 +136,6 @@ func NewComputeTargetTCPProxyRef(ctx context.Context, reader client.Reader, obj
resourceID, actualResourceID)
}
id.External = externalRef
id.parent = &ComputeTargetTCPProxyParent{ProjectID: projectID}
return id, nil
}

Expand All @@ -147,19 +155,15 @@ func (r *ComputeTargetTCPProxyRef) Parent() (*ComputeTargetTCPProxyParent, error

type ComputeTargetTCPProxyParent struct {
ProjectID string
}

type RegionalComputeTargetTCPProxyParent struct {
ProjectID string
Region string
}

func (p *ComputeTargetTCPProxyParent) String() string {
return "projects/" + p.ProjectID + "/global"
}

func (p *RegionalComputeTargetTCPProxyParent) String() string {
return "projects/" + p.ProjectID + "/regions/" + p.Region
if p.Region == "global" {
return "projects/" + p.ProjectID + "/global"
} else {
return "projects/" + p.ProjectID + "/regions/" + p.Region
}
}

func asComputeTargetTCPProxyExternal(parent *ComputeTargetTCPProxyParent, resourceID string) (external string) {
Expand All @@ -169,28 +173,22 @@ func asComputeTargetTCPProxyExternal(parent *ComputeTargetTCPProxyParent, resour
func parseComputeTargetTCPProxyExternal(external string) (parent *ComputeTargetTCPProxyParent, resourceID string, err error) {
external = strings.TrimPrefix(external, "/")
tokens := strings.Split(external, "/")
if len(tokens) != 5 || tokens[0] != "projects" || tokens[3] != "targetTcpProxies" {
return nil, "", fmt.Errorf("format of ComputeTargetTCPProxy external=%q was not known (use projects/<projectId>/global/targetTcpProxies/<targettcpproxyID>)", external)
}
parent = &ComputeTargetTCPProxyParent{
ProjectID: tokens[1],
if len(tokens) == 5 && tokens[0] == "projects" && tokens[3] == "targetTcpProxies" {
parent = &ComputeTargetTCPProxyParent{
ProjectID: tokens[1],
}
resourceID = tokens[4]
return parent, resourceID, nil
} else if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "regions" && tokens[4] == "targetTcpProxies" {
parent = &ComputeTargetTCPProxyParent{
ProjectID: tokens[1],
Region: tokens[3],
}
resourceID = tokens[5]
return parent, resourceID, nil
}
resourceID = tokens[4]
return parent, resourceID, nil
}
return nil, "", fmt.Errorf("ExternalRef format invalid: %s", external)

func parseRegionalComputeTargetTCPProxyExternal(external string) (parent *RegionalComputeTargetTCPProxyParent, resourceID string, err error) {
external = strings.TrimPrefix(external, "/")
tokens := strings.Split(external, "/")
if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "regions" || tokens[4] != "targetTcpProxies" {
return nil, "", fmt.Errorf("format of ComputeTargetTCPProxy external=%q was not known (use projects/<projectId>/regions/<region>/targetTcpProxies/<targettcpproxyID>)", external)
}
parent = &RegionalComputeTargetTCPProxyParent{
ProjectID: tokens[1],
Region: tokens[3],
}
resourceID = tokens[5]
return parent, resourceID, nil
}

func valueOf[T any](t *T) T {
Expand Down
15 changes: 0 additions & 15 deletions apis/compute/v1beta1/zz_generated.deepcopy.go

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

138 changes: 138 additions & 0 deletions mockgcp/mockcompute/regionaltargettcpproxyv1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mockcompute

import (
"context"
"strings"

"github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/common/projects"
pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/cloud/compute/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)

type RegionalTargetTcpProxyV1 struct {
*MockService
pb.UnimplementedRegionTargetTcpProxiesServer
}

func (s *RegionalTargetTcpProxyV1) Get(ctx context.Context, req *pb.GetRegionTargetTcpProxyRequest) (*pb.TargetTcpProxy, error) {
reqName := "projects/" + req.GetProject() + "/regions/" + req.GetRegion() + "/targetTcpProxies/" + req.GetTargetTcpProxy()
name, err := s.parseRegionalTargetTcpProxyName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()

obj := &pb.TargetTcpProxy{}
if err := s.storage.Get(ctx, fqn, obj); err != nil {
return nil, status.Errorf(codes.NotFound, "The resource '%s' was not found", fqn)
}

return obj, nil
}

func (s *RegionalTargetTcpProxyV1) Insert(ctx context.Context, req *pb.InsertRegionTargetTcpProxyRequest) (*pb.Operation, error) {
reqName := "projects/" + req.GetProject() + "/regions/" + req.GetRegion() + "/targetTcpProxies/" + req.GetTargetTcpProxyResource().GetName()
name, err := s.parseRegionalTargetTcpProxyName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()

id := s.generateID()

obj := proto.Clone(req.GetTargetTcpProxyResource()).(*pb.TargetTcpProxy)
obj.SelfLink = PtrTo("https://www.googleapis.com/compute/v1/" + name.String())
obj.CreationTimestamp = PtrTo(s.nowString())
obj.Id = &id
obj.Kind = PtrTo("compute#targetTcpProxy")
obj.Region = PtrTo("https://www.googleapis.com/compute/v1/projects/${projectId}/regions/" + req.GetRegion())

if err := s.storage.Create(ctx, fqn, obj); err != nil {
return nil, err
}

op := &pb.Operation{
TargetId: obj.Id,
TargetLink: obj.SelfLink,
OperationType: PtrTo("insert"),
User: PtrTo("[email protected]"),
}
return s.startRegionalLRO(ctx, name.Project.ID, name.Region, op, func() (proto.Message, error) {
return obj, nil
})
}

func (s *RegionalTargetTcpProxyV1) Delete(ctx context.Context, req *pb.DeleteRegionTargetTcpProxyRequest) (*pb.Operation, error) {
reqName := "projects/" + req.GetProject() + "/regions/" + req.GetRegion() + "/targetTcpProxies/" + req.GetTargetTcpProxy()
name, err := s.parseRegionalTargetTcpProxyName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()

deleted := &pb.TargetTcpProxy{}
if err := s.storage.Delete(ctx, fqn, deleted); err != nil {
return nil, err
}

op := &pb.Operation{
TargetId: deleted.Id,
TargetLink: deleted.SelfLink,
OperationType: PtrTo("delete"),
User: PtrTo("[email protected]"),
}
return s.startRegionalLRO(ctx, name.Project.ID, name.Region, op, func() (proto.Message, error) {
return deleted, nil
})
}

type regionalTargetTcpProxyName struct {
Project *projects.ProjectData
Region string
Name string
}

func (n *regionalTargetTcpProxyName) String() string {
return "projects/" + n.Project.ID + "/regions/" + n.Region + "/targetTcpProxies/" + n.Name
}

// parseRegionalTargetTcpProxyName parses a string into a targetTcpProxyName.
// The expected form is `projects/*/regions/*/targetTcpProxies/*`.
func (s *MockService) parseRegionalTargetTcpProxyName(name string) (*regionalTargetTcpProxyName, error) {
tokens := strings.Split(name, "/")

if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "regions" && tokens[4] == "targetTcpProxies" {
project, err := s.Projects.GetProjectByID(tokens[1])
if err != nil {
return nil, err
}
name := &regionalTargetTcpProxyName{
Project: project,
Region: tokens[3],
Name: tokens[5],
}

return name, nil
} else {
return nil, status.Errorf(codes.InvalidArgument, "name %q is not valid", name)
}
}
1 change: 1 addition & 0 deletions mockgcp/mockcompute/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func (s *MockService) Register(grpcServer *grpc.Server) {
pb.RegisterRegionSslCertificatesServer(grpcServer, &RegionalSSLCertificatesV1{MockService: s})
pb.RegisterTargetSslProxiesServer(grpcServer, &TargetSslProxyV1{MockService: s})
pb.RegisterTargetTcpProxiesServer(grpcServer, &GlobalTargetTcpProxyV1{MockService: s})
pb.RegisterRegionTargetTcpProxiesServer(grpcServer, &RegionalTargetTcpProxyV1{MockService: s})

pb.RegisterServiceAttachmentsServer(grpcServer, &RegionalServiceAttachmentV1{MockService: s})

Expand Down
Loading

0 comments on commit 149e141

Please sign in to comment.