Skip to content

Commit

Permalink
fix ComputeTCPTargetProxy Reference and Identity
Browse files Browse the repository at this point in the history
  • Loading branch information
gemmahou committed Dec 19, 2024
1 parent 10fabf0 commit b7d7bd1
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 200 deletions.
3 changes: 2 additions & 1 deletion apis/compute/v1beta1/computefirewallpolicyrule_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"strconv"
"strings"

"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common"
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 Down Expand Up @@ -105,7 +106,7 @@ func NewComputeFirewallPolicyRuleRef(ctx context.Context, reader client.Reader,
priority := obj.Spec.Priority

// Use approved External
externalRef := valueOf(obj.Status.ExternalRef)
externalRef := common.ValueOf(obj.Status.ExternalRef)
if externalRef == "" {
id.External = asComputeFirewallPolicyRuleExternal(id.parent, priority)
return id, nil
Expand Down
92 changes: 92 additions & 0 deletions apis/compute/v1beta1/targettcpproxy_identity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// 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 v1beta1

import (
"context"
"fmt"

"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common"
refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type TargetTCPProxyIdentity struct {
id string
parent *TargetTCPProxyParent
}

func (i *TargetTCPProxyIdentity) String() string {
return i.parent.String() + "/targetTcpProxies/" + i.id
}

func (r *TargetTCPProxyIdentity) Parent() *TargetTCPProxyParent {
return r.parent
}

func (r *TargetTCPProxyIdentity) ID() string {
return r.id
}

type TargetTCPProxyParent struct {
ProjectID string
Location string
}

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

func NewTargetTCPProxyIdentity(ctx context.Context, reader client.Reader, obj *ComputeTargetTCPProxy, u *unstructured.Unstructured) (*TargetTCPProxyIdentity, error) {
// Get Parent
projectID, err := refsv1beta1.ResolveProjectID(ctx, reader, u)
if err != nil {
return nil, err
}
// Get desired ID
resourceID := common.ValueOf(obj.Spec.ResourceID)
if resourceID == "" {
resourceID = obj.GetName()
}
if resourceID == "" {
return nil, fmt.Errorf("cannot resolve resource ID")
}

// Use approved External
externalRef := common.ValueOf(obj.Status.ExternalRef)
if externalRef != "" {
actualIdentity, err := parseTargetTCPProxyExternal(externalRef)
if err != nil {
return nil, err
}
if actualIdentity.parent.ProjectID != projectID {
return nil, fmt.Errorf("spec.projectRef changed, expect %s, got %s", actualIdentity.parent.ProjectID, projectID)
}
if actualIdentity.id != resourceID {
return nil, fmt.Errorf("cannot reset `metadata.name` or `spec.resourceID` to %s, since it has already assigned to %s",
resourceID, actualIdentity.id)
}
}

return &TargetTCPProxyIdentity{
parent: &TargetTCPProxyParent{ProjectID: projectID},
id: resourceID,
}, nil
}
128 changes: 15 additions & 113 deletions apis/compute/v1beta1/targettcpproxy_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"
"strings"

"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common"
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 @@ -28,11 +27,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)

var _ refsv1beta1.ExternalNormalizer = &ComputeTargetTCPProxyRef{}
var _ refsv1beta1.ExternalNormalizer = &TargetTCPProxyRef{}

// ComputeTargetTCPProxyRef defines the resource reference to ComputeTargetTCPProxy, which "External" field
// TargetTCPProxyRef defines the resource reference to ComputeTargetTCPProxy, which "External" field
// holds the GCP identifier for the KRM object.
type ComputeTargetTCPProxyRef struct {
type TargetTCPProxyRef struct {
// A reference to an externally managed ComputeTargetTCPProxy resource.
// Should be in the format "projects/{{projectID}}/global/targetTcpProxies/{{targettcpproxyID}}"
// or "projects/{{projectID}}/regions/{{region}}/targetTcpProxies/{{targettcpproxyID}}".
Expand All @@ -43,20 +42,18 @@ type ComputeTargetTCPProxyRef struct {

// The namespace of a ComputeTargetTCPProxy resource.
Namespace string `json:"namespace,omitempty"`

parent *ComputeTargetTCPProxyParent
}

// NormalizedExternal provision the "External" value for other resource that depends on ComputeTargetTCPProxy.
// If the "External" is given in the other resource's spec.ComputeTargetTCPProxyRef, the given value will be used.
// Otherwise, the "Name" and "Namespace" will be used to query the actual ComputeTargetTCPProxy object from the cluster.
func (r *ComputeTargetTCPProxyRef) NormalizedExternal(ctx context.Context, reader client.Reader, otherNamespace string) (string, error) {
func (r *TargetTCPProxyRef) NormalizedExternal(ctx context.Context, reader client.Reader, otherNamespace string) (string, error) {
if r.External != "" && r.Name != "" {
return "", fmt.Errorf("cannot specify both name and external on %s reference", ComputeTargetTCPProxyGVK.Kind)
}
// From given External
if r.External != "" {
if _, _, err := parseComputeTargetTCPProxyExternal(r.External); err != nil {
if _, err := parseTargetTCPProxyExternal(r.External); err != nil {
return "", err
}
return r.External, nil
Expand Down Expand Up @@ -87,114 +84,19 @@ func (r *ComputeTargetTCPProxyRef) NormalizedExternal(ctx context.Context, reade
return r.External, nil
}

// New builds a ComputeTargetTCPProxyRef from the Config Connector ComputeTargetTCPProxy object.
func NewComputeTargetTCPProxyRef(ctx context.Context, reader client.Reader, obj *ComputeTargetTCPProxy, u *unstructured.Unstructured) (*ComputeTargetTCPProxyRef, error) {
id := &ComputeTargetTCPProxyRef{}

// Get Parent
projectID, err := refsv1beta1.ResolveProjectID(ctx, reader, u)
if projectID == "" {
return nil, fmt.Errorf("cannot resolve project")
}

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

// Get desired ID
resourceID := valueOf(obj.Spec.ResourceID)
if resourceID == "" {
resourceID = obj.GetName()
}
if resourceID == "" {
return nil, fmt.Errorf("cannot resolve resource ID")
}

// Use approved External
externalRef := valueOf(obj.Status.ExternalRef)
if externalRef == "" {
id.External = asComputeTargetTCPProxyExternal(id.parent, resourceID)
return id, nil
}

// Validate desired with actual
actualParent, actualResourceID, err := parseComputeTargetTCPProxyExternal(externalRef)
if err != nil {
return nil, err
}
if actualParent.ProjectID != projectID {
return nil, fmt.Errorf("spec.projectRef changed, expect %s, got %s", actualParent.ProjectID, projectID)
}

if actualResourceID != resourceID {
return nil, fmt.Errorf("cannot reset `metadata.name` or `spec.resourceID` to %s, since it has already assigned to %s",
resourceID, actualResourceID)
}
id.External = externalRef
return id, nil
}

func (r *ComputeTargetTCPProxyRef) Parent() (*ComputeTargetTCPProxyParent, error) {
if r.parent != nil {
return r.parent, nil
}
if r.External != "" {
parent, _, err := parseComputeTargetTCPProxyExternal(r.External)
if err != nil {
return nil, err
}
return parent, nil
}
return nil, fmt.Errorf("ComputeTargetTCPProxyRef not initialized from `NewComputeTargetTCPProxyRef` or `NormalizedExternal`")
}

type ComputeTargetTCPProxyParent struct {
ProjectID string
Location string
}

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

func asComputeTargetTCPProxyExternal(parent *ComputeTargetTCPProxyParent, resourceID string) (external string) {
return parent.String() + "/targetTcpProxies/" + resourceID
}

func parseComputeTargetTCPProxyExternal(external string) (parent *ComputeTargetTCPProxyParent, resourceID string, err error) {
func parseTargetTCPProxyExternal(external string) (*TargetTCPProxyIdentity, error) {
external = strings.TrimPrefix(external, "/")
tokens := strings.Split(external, "/")
if len(tokens) == 5 && tokens[0] == "projects" && tokens[2] == "global" && tokens[3] == "targetTcpProxies" {
parent = &ComputeTargetTCPProxyParent{
ProjectID: tokens[1],
Location: "global",
}
resourceID = tokens[4]
return parent, resourceID, nil
return &TargetTCPProxyIdentity{
parent: &TargetTCPProxyParent{ProjectID: tokens[1], Location: "global"},
id: tokens[4],
}, nil
} else if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "regions" && tokens[4] == "targetTcpProxies" {
parent = &ComputeTargetTCPProxyParent{
ProjectID: tokens[1],
Location: tokens[3],
}
resourceID = tokens[5]
return parent, resourceID, nil
}
return nil, "", fmt.Errorf("ExternalRef format invalid: %s", external)

}

func valueOf[T any](t *T) T {
var zeroVal T
if t == nil {
return zeroVal
return &TargetTCPProxyIdentity{
parent: &TargetTCPProxyParent{ProjectID: tokens[1], Location: tokens[3]},
id: tokens[5],
}, nil
}
return *t
return nil, fmt.Errorf("format of ComputeTargetTCPProxy external=%q was not known (use projects/{{projectID}}/global/targetTcpProxies/{{targettcpproxyID}} or projects/{{projectID}}/regions/{{region}}/targetTcpProxies/{{targettcpproxyID}})", external)
}
85 changes: 50 additions & 35 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.

Loading

0 comments on commit b7d7bd1

Please sign in to comment.