Skip to content

Commit

Permalink
Merge branch 'GoogleCloudPlatform:master' into configToBeta
Browse files Browse the repository at this point in the history
  • Loading branch information
nb-goog authored Nov 13, 2024
2 parents f0747be + d812f9f commit 2f8d4ce
Show file tree
Hide file tree
Showing 473 changed files with 33,629 additions and 5,956 deletions.
6 changes: 4 additions & 2 deletions apis/bigqueryconnection/v1alpha1/connection_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ type Parent struct {
type BigQueryConnectionConnectionSpec struct {
Parent `json:",inline"`

// The BigQuery ConnectionID. This is a server-generated ID in the UUID format.
// If not provided, ConfigConnector will create a new Connection and store the UUID in `status.serviceGeneratedID` field.
// Immutable. Optional.
// The BigQuery Connection ID used for resource creation or acquisition.
// For creation: If specified, this value is used as the connection ID. If not provided, a UUID will be generated and assigned as the connection ID.
// For acquisition: This field must be provided to identify the connection resource to acquire.
ResourceID *string `json:"resourceID,omitempty"`

// User provided display name for the connection.
Expand Down
74 changes: 37 additions & 37 deletions apis/bigqueryconnection/v1beta1/connection_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
"github.com/google/uuid"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -44,46 +43,33 @@ func NewBigQueryConnectionConnectionRef(ctx context.Context, reader client.Reade
// Get location
location := obj.Spec.Location

// Get desired service-generated ID from spec
desiredServiceID := direct.ValueOf(obj.Spec.ResourceID)
if desiredServiceID != "" {
if _, err := uuid.Parse(desiredServiceID); err != nil {
return nil, fmt.Errorf("spec.resourceID should be in a UUID format, got %s ", desiredServiceID)
}
}
// Get desired connection ID from spec
desiredID := direct.ValueOf(obj.Spec.ResourceID)

// Get externalReference
// Validate status.externalRef
externalRef := direct.ValueOf(obj.Status.ExternalRef)
if externalRef != "" {
tokens := strings.Split(externalRef, "/")

if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "connections" {
return nil, fmt.Errorf("externalRef should be projects/<project>/locations/<location>/connections/<Connection>, got %s", externalRef)
actualProject, actualLocation, actualID, err := parseExternal(externalRef)
if err != nil {
return nil, err
}
id.parent = "projects/" + tokens[1] + "/locations/" + tokens[3]

// Validate spec parent and resourceID field if the resource is already reconcilied with a GCP Connection resource.
if tokens[1] != projectID {
return nil, fmt.Errorf("spec.projectRef changed, expect %s, got %s",
tokens[1], projectID)
if projectID != actualProject {
return nil, fmt.Errorf("spec.projectRef changed, expect %s, got %s", projectID, actualProject)
}
if tokens[3] != location {
return nil, fmt.Errorf("spec.location changed, expect %s, got %s",
tokens[3], location)
if location != actualLocation {
return nil, fmt.Errorf("spec.location changed, expect %s, got %s", location, actualLocation)
}
if desiredServiceID != "" && tokens[5] != desiredServiceID {
// Service generated ID shall not be reset in the same BigQueryConnectionConnection.
if desiredID != "" && desiredID != actualID {
// Connection ID shall not be reset in the same BigQueryConnectionConnection.
// TODO: what if multiple BigQueryConnectionConnection points to the same GCP Connection?
return nil, fmt.Errorf("cannot reset `spec.resourceID` to %s, since it has already acquired the Connection %s",
desiredServiceID, tokens[5])
desiredID, actualID)
}
id.External = externalRef
return id, nil
}
id.parent = "projects/" + projectID + "/locations/" + location
if desiredServiceID != "" {
id.External = id.parent + "/connections/" + desiredServiceID
}
id.External = "projects/" + projectID + "/locations/" + location + "/connections/" + desiredID
return id, nil
}

Expand All @@ -100,26 +86,40 @@ type BigQueryConnectionConnectionRef struct {
Name string `json:"name,omitempty"`
// The `namespace` of a `BigQueryConnectionConnection` resource.
Namespace string `json:"namespace,omitempty"`
}

parent string
func parseExternal(external string) (string, string, string, error) {
tokens := strings.Split(external, "/")
if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "connections" {
return "", "", "", fmt.Errorf("external should be projects/<project>/locations/<location>/connections/<Connection>, got %s", external)
}
return tokens[1], tokens[3], tokens[5], nil
}

func (r *BigQueryConnectionConnectionRef) Parent() (string, error) {
if r.parent != "" {
return r.parent, nil
}
if r.External != "" {
r.External = strings.TrimPrefix(r.External, "/")
tokens := strings.Split(r.External, "/")
if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "connections" {
return "", fmt.Errorf("format of BigQueryConnectionConnection external=%q was not known (use projects/<projectId>/locations/<location>/connections/<connectionID>)", r.External)
project, location, _, err := parseExternal(r.External)
if err != nil {
return "", err
}
r.parent = "projects/" + tokens[1] + "/locations/" + tokens[3]
return r.parent, nil
return "projects/" + project + "/locations/" + location, nil
}
return "", fmt.Errorf("BigQueryConnectionConnectionRef not normalized to External form or not created from `New()`")
}

// ConnectionID returns the connection ID, a boolean indicating whether the connection ID is specified by user (or generated by service), and an error.
func (r *BigQueryConnectionConnectionRef) ConnectionID() (string, bool, error) {
if r.External != "" {
_, _, id, err := parseExternal(r.External)
if err != nil {
return "", false, err
}
return id, id != "", nil
}
return "", false, fmt.Errorf("BigQueryConnectionConnectionRef not normalized to External form or not created from `New()`")
}

// NormalizedExternal provision the "External" value.
// If the "External" comes from the ConfigConnector object, it has to acquire or reconcile with the GCP resource already.
func (r *BigQueryConnectionConnectionRef) NormalizedExternal(ctx context.Context, reader client.Reader, othernamespace string) (string, error) {
Expand Down
6 changes: 4 additions & 2 deletions apis/bigqueryconnection/v1beta1/connection_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ type Parent struct {
type BigQueryConnectionConnectionSpec struct {
Parent `json:",inline"`

// The BigQuery ConnectionID. This is a server-generated ID in the UUID format.
// If not provided, ConfigConnector will create a new Connection and store the UUID in `status.serviceGeneratedID` field.
// Immutable. Optional.
// The BigQuery Connection ID used for resource creation or acquisition.
// For creation: If specified, this value is used as the connection ID. If not provided, a UUID will be generated and assigned as the connection ID.
// For acquisition: This field must be provided to identify the connection resource to acquire.
ResourceID *string `json:"resourceID,omitempty"`

// User provided display name for the connection.
Expand Down
118 changes: 76 additions & 42 deletions apis/refs/v1beta1/computerefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ package v1beta1
import (
"context"
"fmt"
"strconv"
"strings"

resourcemanager "cloud.google.com/go/resourcemanager/apiv3"
resourcemanagerpb "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand All @@ -44,61 +47,87 @@ type ComputeNetworkRef struct {
Name string `json:"name,omitempty"`
/* The `namespace` field of a `ComputeNetwork` resource. */
Namespace string `json:"namespace,omitempty"`

ProjectNumber string `json:"-"`
}

func (networkRef *ComputeNetworkRef) WithProjectNumber() string {
_, id, _ := ParseComputeNetworkExternal(networkRef.External)
return buildNetworkExternal(networkRef.ProjectNumber, id)
}

type ComputeNetwork struct {
Project string
ComputeNetworkID string
}

func (c *ComputeNetwork) String() string {
return buildNetworkExternal(c.Project, c.ComputeNetworkID)
type ComputeNetworkID struct {
Project string
Network string
}

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

func ParseComputeNetworkExternal(external string) (string, string, error) {
func ParseComputeNetworkID(external string) (*ComputeNetworkID, error) {
if external == "" {
return "", "", fmt.Errorf("parse empty ComputeNetwork external value")
return nil, fmt.Errorf("empty ComputeNetwork external value")
}
external = fixStaleExternalFormat(external)
tokens := strings.Split(external, "/")
if len(tokens) == 5 && tokens[0] == "projects" && tokens[2] == "global" && tokens[3] == "networks" {
return tokens[1], tokens[4], nil
return &ComputeNetworkID{
Project: tokens[1],
Network: tokens[4],
}, nil
}
return "", "", fmt.Errorf("format of computenetwork external=%q was not known (use projects/<project>/global/networks/<networkid>)", external)
return nil, fmt.Errorf("format of computenetwork external=%q was not known (use projects/<project>/global/networks/<networkid>)", external)
}

func ResolveComputeNetwork(ctx context.Context, reader client.Reader, src client.Object, ref *ComputeNetworkRef) (*ComputeNetwork, error) {
// ConvertToProjectNumber converts the external reference to use a project number.
func (ref *ComputeNetworkRef) ConvertToProjectNumber(ctx context.Context, projectsClient *resourcemanager.ProjectsClient) error {
if ref == nil {
return nil, nil
return nil
}

id, err := ParseComputeNetworkID(ref.External)
if err != nil {
return err
}

// Check if the project number is already a valid integer
// If not, we need to look it up
projectNumber, err := strconv.ParseInt(id.Project, 10, 64)
if err != nil {
req := &resourcemanagerpb.GetProjectRequest{
Name: "projects/" + id.Project,
}
project, err := projectsClient.GetProject(ctx, req)
if err != nil {
return fmt.Errorf("error getting project %q: %w", req.Name, err)
}
n, err := strconv.ParseInt(strings.TrimPrefix(project.Name, "projects/"), 10, 64)
if err != nil {
return fmt.Errorf("error parsing project number for %q: %w", project.Name, err)
}
projectNumber = n
}
id.Project = strconv.FormatInt(projectNumber, 10)
ref.External = id.String()
return nil
}

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

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

if ref.External != "" {
project, networkID, err := ParseComputeNetworkExternal(ref.External)
id, err := ParseComputeNetworkID(ref.External)
if err != nil {
return nil, err
return err
}
*ref = ComputeNetworkRef{
External: id.String(),
}
return &ComputeNetwork{
Project: project,
ComputeNetworkID: networkID}, nil
return nil
}

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

key := types.NamespacedName{
Expand All @@ -109,32 +138,37 @@ 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, k8s.NewReferenceNotFoundError(computenetwork.GroupVersionKind(), key)
return k8s.NewReferenceNotFoundError(computeNetwork.GroupVersionKind(), key)
}
return nil, fmt.Errorf("error reading referenced ComputeNetwork %v: %w", key, err)
return fmt.Errorf("error reading referenced ComputeNetwork %v: %w", key, err)
}

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

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

id := ComputeNetworkID{
Project: projectID,
Network: resourceID,
}
*ref = ComputeNetworkRef{
External: id.String(),
}
return nil
}

type ComputeSubnetworkRef struct {
Expand Down
Loading

0 comments on commit 2f8d4ce

Please sign in to comment.