Skip to content

Commit

Permalink
direct controller for ComputeForwardingRule
Browse files Browse the repository at this point in the history
  • Loading branch information
gemmahou committed Aug 3, 2024
1 parent 07c0bcc commit 64c01cf
Show file tree
Hide file tree
Showing 10 changed files with 756 additions and 145 deletions.
2 changes: 1 addition & 1 deletion apis/compute/v1beta1/computeforwardingrule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var (
// AddToScheme is a global function that registers this API group & version to a scheme
AddToScheme = SchemeBuilder.AddToScheme

ComputeForwardingRuleGVK = schema.GroupVersionKind{
GroupVersionKind = schema.GroupVersionKind{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Kind: "ComputeForwardingRule",
Expand Down
235 changes: 214 additions & 21 deletions apis/refs/v1beta1/computerefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
)

type ComputeNetworkRef struct {
/* The compute network selflink of form "projects/<project>/global/networks/<network>", when not managed by KCC. */
/* The compute network id of form "projects/<project>/global/networks/<network>", when not managed by KCC. */
External string `json:"external,omitempty"`
/* The `name` field of a `ComputeNetwork` resource. */
Name string `json:"name,omitempty"`
Expand All @@ -39,7 +39,7 @@ type ComputeNetwork struct {
ComputeNetworkID string
}

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

Expand Down Expand Up @@ -74,31 +74,31 @@ func ResolveComputeNetwork(ctx context.Context, reader client.Reader, src client
key.Namespace = src.GetNamespace()
}

computenetwork := &unstructured.Unstructured{}
computenetwork.SetGroupVersionKind(schema.GroupVersionKind{
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 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)
computeNetworkID, err := GetResourceID(computeNetwork)
if err != nil {
return nil, err
}

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

Expand All @@ -120,6 +120,102 @@ type ComputeAddressRef struct {
Namespace string `json:"namespace,omitempty"`
}

type ComputeAddress struct {
Project string
Location string
ComputeAddressID string
Address string
}

func (c *ComputeAddress) Url() string {
if c.Location == "global" {
return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/addresses/%s", c.Project, c.ComputeAddressID)
}
return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/regions/%s/addresses/%s", c.Project, c.Location, c.ComputeAddressID)
}

func (c *ComputeAddress) GetAddress() string {
return fmt.Sprintf("%s", c.Address)
}

func ResolveComputeAddress(ctx context.Context, reader client.Reader, src client.Object, ref *ComputeAddressRef) (*ComputeAddress, error) {
if ref == nil {
return nil, nil
}

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

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

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

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

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

computeAddressID, err := GetResourceID(computeAddress)
if err != nil {
return nil, err
}

computeAddressProjectID, err := ResolveProjectID(ctx, reader, computeAddress)
if err != nil {
return nil, err
}

computeAddressLocation, err := getLocation(computeAddress)
if err != nil {
return nil, err
}

address, err := getAddress(computeAddress)
if err != nil {
return nil, err
}

return &ComputeAddress{
Project: computeAddressProjectID,
Location: computeAddressLocation,
ComputeAddressID: computeAddressID,
Address: address,
}, nil
}

type ComputeBackendServiceRef struct {
/* The ComputeBackendService selflink in the form "projects/{{project}}/global/backendServices/{{name}}" or "projects/{{project}}/regions/{{region}}/backendServices/{{name}}" when not managed by KCC. */
External string `json:"external,omitempty"`
Expand Down Expand Up @@ -162,11 +258,11 @@ type ComputeTargetHTTPProxy struct {
ComputeTargetHTTPProxyID string
}

func (c *ComputeTargetHTTPProxy) String() string {
func (c *ComputeTargetHTTPProxy) Url() string {
if c.Location == "global" {
return fmt.Sprintf("projects/%s/global/targetHttpProxies/%s", c.Project, c.ComputeTargetHTTPProxyID)
return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/targetHttpProxies/%s", c.Project, c.ComputeTargetHTTPProxyID)
}
return fmt.Sprintf("projects/%s/location/%s/targetHttpProxies/%s", c.Project, c.Location, c.ComputeTargetHTTPProxyID)
return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/regions/%s/targetHttpProxies/%s", c.Project, c.Location, c.ComputeTargetHTTPProxyID)
}

func ResolveTargetHTTPProxy(ctx context.Context, reader client.Reader, src client.Object, ref *ComputeTargetHTTPProxyRef) (*ComputeTargetHTTPProxy, error) {
Expand All @@ -176,7 +272,7 @@ func ResolveTargetHTTPProxy(ctx context.Context, reader client.Reader, src clien

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

tokens := strings.Split(ref.External, "/")
Expand All @@ -191,7 +287,7 @@ func ResolveTargetHTTPProxy(ctx context.Context, reader client.Reader, src clien
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)
return nil, fmt.Errorf("format of ComputeTargetHTTPProxy external=%q was not known (use projects/<projectId>/global/targetHttpProxies/<proxyId> or projects/<projectId>/regions/<region>/targetHttpProxies/<proxyId>)", ref.External)
}

if ref.Name == "" {
Expand Down Expand Up @@ -242,7 +338,7 @@ func ResolveTargetHTTPProxy(ctx context.Context, reader client.Reader, src clien
}

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. */
/* 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"`
/* The `name` field of a `ComputeTargetHTTPSProxy` resource. */
Name string `json:"name,omitempty"`
Expand All @@ -251,7 +347,7 @@ type ComputeTargetHTTPSProxyRef struct {
}

type ComputeTargetSSLProxyRef struct {
/* The ComputeTargetSSLProxy selflink in the form "projects/{{project}}/global/targetSslProxies/{{name}}" when not managed by KCC. */
/* The ComputeTargetSSLProxy selfLink in the form "projects/{{project}}/global/targetSslProxies/{{name}}" when not managed by KCC. */
External string `json:"external,omitempty"`
/* The `name` field of a `ComputeTargetSSLProxy` resource. */
Name string `json:"name,omitempty"`
Expand All @@ -260,7 +356,7 @@ type ComputeTargetSSLProxyRef struct {
}

type ComputeTargetTCPProxyRef struct {
/* The ComputeTargetTCPProxy selflink in the form "projects/{{project}}/global/targetTcpProxies/{{name}}" or "projects/{{project}}/regions/{{region}}/targetTcpProxies/{{name}}" when not managed by KCC. */
/* The ComputeTargetTCPProxy selfLink in the form "projects/{{project}}/global/targetTcpProxies/{{name}}" or "projects/{{project}}/regions/{{region}}/targetTcpProxies/{{name}}" when not managed by KCC. */
External string `json:"external,omitempty"`
/* The `name` field of a `ComputeTargetTCPProxy` resource. */
Name string `json:"name,omitempty"`
Expand All @@ -269,23 +365,120 @@ type ComputeTargetTCPProxyRef struct {
}

type ComputeTargetVPNGatewayRef struct {
/* The ComputeTargetVPNGateway selflink in the form "projects/{{project}}/regions/{{region}}/targetVpnGateways/{{name}}" when not managed by KCC. */
/* The ComputeTargetVPNGateway selfLink in the form "projects/{{project}}/regions/{{region}}/targetVpnGateways/{{name}}" when not managed by KCC. */
External string `json:"external,omitempty"`
/* The `name` field of a `ComputeTargetVPNGateway` resource. */
Name string `json:"name,omitempty"`
/* The `namespace` field of a `ComputeTargetVPNGateway` resource. */
Namespace string `json:"namespace,omitempty"`
}

type ComputeTargetVPNGateway struct {
Project string
Location string
ComputeTargetVPNGatewayID string
}

func (c *ComputeTargetVPNGateway) Url() string {
return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/regions/%s/targetVpnGateways/%s", c.Project, c.Location, c.ComputeTargetVPNGatewayID)
}

func ResolveComputeTargetVPNGateway(ctx context.Context, reader client.Reader, src client.Object, ref *ComputeTargetVPNGatewayRef) (*ComputeTargetVPNGateway, error) {
if ref == nil {
return nil, nil
}

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

tokens := strings.Split(ref.External, "/")
if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "location" && tokens[4] == "targetVpnGateways" {
return &ComputeTargetVPNGateway{
Project: tokens[1],
Location: tokens[3],
ComputeTargetVPNGatewayID: tokens[5]}, nil
}
return nil, fmt.Errorf("format of ComputeTargetVPNGateway external=%q was not known (use projects/<projectId>/regions/<region>/targetVpnGateways/<gatewayId>)", ref.External)
}

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

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

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

computeTargetVPNGatewayID, err := GetResourceID(computeTargetVPNGateway)
if err != nil {
return nil, err
}

computeTargetVPNGatewayProjectID, err := ResolveProjectID(ctx, reader, computeTargetVPNGateway)
if err != nil {
return nil, err
}

computeTargetVPNGatewayLocation, err := getLocation(computeTargetVPNGateway)
if err != nil {
return nil, err
}

return &ComputeTargetVPNGateway{
Project: computeTargetVPNGatewayProjectID,
Location: computeTargetVPNGatewayLocation,
ComputeTargetVPNGatewayID: computeTargetVPNGatewayID,
}, nil
}

// 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")
location, found, 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)
return "", fmt.Errorf("cannot get location for referenced %s %v: %s", obj.GetKind(), obj.GetNamespace(), err)

Check failure on line 457 in apis/refs/v1beta1/computerefs.go

View workflow job for this annotation

GitHub Actions / lint

non-wrapping format verb for fmt.Errorf. Use `%w` to format errors (errorlint)
}
if !found {
// if region is set, use its value as location
location, found, err = unstructured.NestedString(obj.Object, "spec", "region")
if err != nil {
return "", fmt.Errorf("cannot get region for referenced %s %v: %s", obj.GetKind(), obj.GetNamespace(), err)

Check failure on line 463 in apis/refs/v1beta1/computerefs.go

View workflow job for this annotation

GitHub Actions / lint

non-wrapping format verb for fmt.Errorf. Use `%w` to format errors (errorlint)
}
if !found {
return "", fmt.Errorf("cannot get location or region for referenced %s %v (spec.location or spec.region not set)", obj.GetKind(), obj.GetNamespace())
}
}
if location == "" {
return "", fmt.Errorf("cannot get location for referenced %s %v (spec.location not set)", obj.GetKind(), obj.GetNamespace())
return "", fmt.Errorf("cannot get location or region for referenced %s %v (spec.location or spec.region is empty)", obj.GetKind(), obj.GetNamespace())
}
return location, nil
}

func getAddress(obj *unstructured.Unstructured) (string, error) {
address, _, err := unstructured.NestedString(obj.Object, "spec", "address")
if err != nil {
return "", fmt.Errorf("reading spec.resourceID from %v %v/%v: %w", obj.GroupVersionKind().Kind, obj.GetNamespace(), obj.GetName(), err)
}
if address == "" {
return "", fmt.Errorf("cannot get address for referenced %s %v (spec.address is empty)", obj.GetKind(), obj.GetNamespace())
}
return address, nil
}
2 changes: 1 addition & 1 deletion pkg/controller/direct/cloudbuild/workerpool_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (m *model) AdapterForObject(ctx context.Context, reader client.Reader, u *u
return nil, err

}
obj.Spec.PrivatePoolConfig.NetworkConfig.PeeredNetworkRef.External = networkRef.String()
obj.Spec.PrivatePoolConfig.NetworkConfig.PeeredNetworkRef.External = networkRef.Id()
}

// Get CloudBuild GCP client
Expand Down
Loading

0 comments on commit 64c01cf

Please sign in to comment.