Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve resource reference(initial PR) #2337

Merged
merged 3 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 0 additions & 138 deletions apis/refs/v1beta1/computenetworkref.go

This file was deleted.

177 changes: 177 additions & 0 deletions apis/refs/v1beta1/computerefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@

package v1beta1

import (
"context"
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
)

type ComputeNetworkRef struct {
/* The compute network selflink of form "projects/<project>/global/networks/<network>", when not managed by KCC. */
External string `json:"external,omitempty"`
Expand All @@ -23,6 +34,74 @@ type ComputeNetworkRef struct {
Namespace string `json:"namespace,omitempty"`
}

type ComputeNetwork struct {
Project string
ComputeNetworkID string
}

func (c *ComputeNetwork) String() string {
return fmt.Sprintf("projects/%s/global/networks/%s", c.Project, c.ComputeNetworkID)
}

func ResolveComputeNetwork(ctx context.Context, reader client.Reader, src client.Object, ref *ComputeNetworkRef) (*ComputeNetwork, error) {
if ref == nil {
return nil, nil
}

if ref.External != "" {
if ref.Name != "" {
return nil, fmt.Errorf("cannot specify both name and external on computenetwork reference")
}

tokens := strings.Split(ref.External, "/")
if len(tokens) == 5 && tokens[0] == "projects" && tokens[2] == "global" && tokens[3] == "networks" {
return &ComputeNetwork{
Project: tokens[1],
ComputeNetworkID: tokens[4]}, nil
}
return nil, fmt.Errorf("format of computenetwork external=%q was not known (use projects/<projectId>/global/networks/<networkid>)", ref.External)
}

if ref.Name == "" {
return nil, fmt.Errorf("must specify either name or external on computenetwork reference")
}

key := types.NamespacedName{
Namespace: ref.Namespace,
Name: ref.Name,
}
if key.Namespace == "" {
key.Namespace = src.GetNamespace()
}

computenetwork := &unstructured.Unstructured{}
computenetwork.SetGroupVersionKind(schema.GroupVersionKind{
Group: "compute.cnrm.cloud.google.com",
Version: "v1beta1",
Kind: "ComputeNetwork",
})
if err := reader.Get(ctx, key, computenetwork); err != nil {
if apierrors.IsNotFound(err) {
return nil, fmt.Errorf("referenced ComputeNetwork %v not found", key)
}
return nil, fmt.Errorf("error reading referenced ComputeNetwork %v: %w", key, err)
}

computenetworkID, err := GetResourceID(computenetwork)
if err != nil {
return nil, err
}

computeNetworkProjectID, err := ResolveProjectID(ctx, reader, computenetwork)
if err != nil {
return nil, err
}
return &ComputeNetwork{
Project: computeNetworkProjectID,
ComputeNetworkID: computenetworkID,
}, nil
}

type ComputeSubnetworkRef struct {
/* The ComputeSubnetwork selflink of form "projects/{{project}}/regions/{{region}}/subnetworks/{{name}}", when not managed by KCC. */
External string `json:"external,omitempty"`
Expand Down Expand Up @@ -77,6 +156,91 @@ type ComputeTargetHTTPProxyRef struct {
Namespace string `json:"namespace,omitempty"`
}

type ComputeTargetHTTPProxy struct {
Project string
Location string
ComputeTargetHTTPProxyID string
}

func (c *ComputeTargetHTTPProxy) String() string {
if c.Location == "global" {
return fmt.Sprintf("projects/%s/global/targetHttpProxies/%s", c.Project, c.ComputeTargetHTTPProxyID)
}
return fmt.Sprintf("projects/%s/location/%s/targetHttpProxies/%s", c.Project, c.Location, c.ComputeTargetHTTPProxyID)
}

func ResolveTargetHTTPProxy(ctx context.Context, reader client.Reader, src client.Object, ref *ComputeTargetHTTPProxyRef) (*ComputeTargetHTTPProxy, error) {
if ref == nil {
return nil, nil
}

if ref.External != "" {
if ref.Name != "" {
return nil, fmt.Errorf("cannot specify both name and external on ComputeNetwork reference")
}

tokens := strings.Split(ref.External, "/")
if len(tokens) == 5 && tokens[0] == "projects" && tokens[2] == "global" && tokens[3] == "targetHttpProxies" {
return &ComputeTargetHTTPProxy{
Project: tokens[1],
Location: "global",
ComputeTargetHTTPProxyID: tokens[4]}, nil
} else if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "location" && tokens[4] == "targetHttpProxies" {
return &ComputeTargetHTTPProxy{
Project: tokens[1],
Location: tokens[3],
ComputeTargetHTTPProxyID: tokens[5]}, nil
}
return nil, fmt.Errorf("format of ComputeTargetHTTPProxy external=%q was not known (use projects/<projectId>/global/targetHttpProxies/<proxyId> or projects/<projectId>/location/<location>/targetHttpProxies/<proxyId>)", ref.External)
}

if ref.Name == "" {
return nil, fmt.Errorf("must specify either name or external on ComputeTargetHTTPProxy reference")
}

key := types.NamespacedName{
Namespace: ref.Namespace,
Name: ref.Name,
}
if key.Namespace == "" {
key.Namespace = src.GetNamespace()
}

computeTargetHTTPProxy := &unstructured.Unstructured{}
computeTargetHTTPProxy.SetGroupVersionKind(schema.GroupVersionKind{
Group: "compute.cnrm.cloud.google.com",
Version: "v1beta1",
Kind: "ComputeTargetHTTPProxy",
})
if err := reader.Get(ctx, key, computeTargetHTTPProxy); err != nil {
if apierrors.IsNotFound(err) {
return nil, fmt.Errorf("referenced ComputeTargetHTTPProxy %v not found", key)
}
return nil, fmt.Errorf("error reading referenced ComputeTargetHTTPProxy %v: %w", key, err)
}

computeTargetHTTPProxyID, err := GetResourceID(computeTargetHTTPProxy)
if err != nil {
return nil, err
}

computeTargetHTTPProxyProjectID, err := ResolveProjectID(ctx, reader, computeTargetHTTPProxy)
if err != nil {
return nil, err
}

computeTargetHTTPProxyLocation, err := getLocation(computeTargetHTTPProxy)
if err != nil {
return nil, err
}

return &ComputeTargetHTTPProxy{
Project: computeTargetHTTPProxyProjectID,
Location: computeTargetHTTPProxyLocation,
ComputeTargetHTTPProxyID: computeTargetHTTPProxyID,
}, nil
}

type ComputeTargetHTTPSProxyRef struct {
/* The ComputeTargetHTTPSProxy selflink in the form "projects/{{project}}/global/targetHttpProxies/{{name}}" or "projects/{{project}}/regions/{{region}}/targetHttpProxies/{{name}}" when not managed by KCC. */
External string `json:"external,omitempty"`
Expand Down Expand Up @@ -112,3 +276,16 @@ type ComputeTargetVPNGatewayRef struct {
/* The `namespace` field of a `ComputeTargetVPNGateway` resource. */
Namespace string `json:"namespace,omitempty"`
}

// TODO(yuhou): Location can be optional. Use provider default location when it's unset.
func getLocation(obj *unstructured.Unstructured) (string, error) {
// TODO(yuhou): field can be "location" or "region".
location, _, err := unstructured.NestedString(obj.Object, "spec", "location")
if err != nil {
return "", fmt.Errorf("cannot get location for referenced %s %v: %w", obj.GetKind(), obj.GetNamespace(), err)
}
if location == "" {
return "", fmt.Errorf("cannot get location for referenced %s %v (spec.location not set)", obj.GetKind(), obj.GetNamespace())
}
return location, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package v1beta1

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

Expand Down
Loading
Loading