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

feat: add direct controller for BigQueryDataTransferConfig #2688

Merged

Conversation

jingyih
Copy link
Collaborator

@jingyih jingyih commented Sep 12, 2024

Fixes #1432

@jingyih jingyih force-pushed the BigQueryDataTransferConfig branch 2 times, most recently from 41af159 to 7fa396f Compare September 13, 2024 01:20
Copy link
Collaborator Author

@jingyih jingyih left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yuwenma I added some notes on special handling for service generated ID.

// Get ResourceID
resourceID := direct.ValueOf(obj.Spec.ResourceID)
if resourceID == "" {
serviceGeneratedID, err := parseServiceGeneratedIDFromExternalRef(obj)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resource ID is service generated. It could be "" prior to resource creation.

if a.id == nil {
return false, nil
}
if a.id.transferConfigID == "" { // resource ID is not yet generated by the GCP service
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

special handling for finding resource prior to being created.

if err != nil {
return fmt.Errorf("error converting %s to BigQueryDataTransferConfigIdentity: %w", created.Name, err)
}
a.id.transferConfigID = serviceGeneratedID
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to write the service generated ID back

if mapCtx.Err() != nil {
return mapCtx.Err()
}
resource.Name = a.id.FullyQualifiedName() // need to pass service generated ID to GCP API
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to pass the service generated ID when updating the resource.

Comment on lines 33 to 38

GroupVersionKind = schema.GroupVersionKind{
Group: GroupVersion.Group,
Version: GroupVersion.Version,
Kind: "BigQueryDataTransferConfig",
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better format could be adding
var BigQueryDataTransferConfigGVK = GroupVersion.WithKind("BigQueryDataTransferConfig") in the _types.go, which is what the latest template does.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. I am updating the controller template in #2692, so that we don't have a undefined GroupVersionKind right after scaffolding the controller code.

@@ -55,7 +55,7 @@ go run ./scripts/crd-tools reflow-descriptions --dir apis/config/crd/

# excluded_resources are resources that are under development for a direct conversion
# we don't modify the CRD just yet for those but will in the future
excluded_resources=("bigquerydatatransferconfig" "securesourcemanagerinstance")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines 100 to 124
if obj.Spec.PubSubTopicRef != nil {
topic, err := refv1beta1.ResolvePubSubTopic(ctx, reader, obj, obj.Spec.PubSubTopicRef)
if err != nil {
return nil, err
}
obj.Spec.PubSubTopicRef.External = topic.String()
}

// Resolve BigQueryDataSet Ref
if obj.Spec.DatasetRef != nil {
dataset, err := refv1beta1.ResolveBigQueryDataset(ctx, reader, obj, obj.Spec.DatasetRef)
if err != nil {
return nil, err
}
obj.Spec.DatasetRef.External = dataset.String()
}

// Resolve KMSCryptoKey Ref
if obj.Spec.EncryptionConfiguration != nil {
kmsCryptoKeyRef, err := refv1beta1.ResolveKMSCryptoKeyRef(ctx, reader, obj, obj.Spec.EncryptionConfiguration.KmsKeyRef)
if err != nil {
return nil, err
}
obj.Spec.EncryptionConfiguration.KmsKeyRef = kmsCryptoKeyRef
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shall move the non-parent depedencies in the create and update calls.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise the presence of the dependency would block the target resource

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, it mainly affects Find() call? In other words, if the dependencies are not present, Create() and Update() will be blocked anyway, but Find() should not be blocked.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It affects Delete. If a reference is missing, it cannot delete the object.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a blocker issue.

Comment on lines 189 to 191
if a.id == nil {
return false, nil
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind explaining what this means?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove this block. I think it was from my previous iteration on how to handle the service generated ID. Thanks for spotting!

}

// Get ResourceID
resourceID := direct.ValueOf(obj.Spec.ResourceID)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you miss a case that metadata.name --> resourceID if spec.resourceID is not given? Or is that not a valid case here? I mean the case that KCC acquire a GCP resource that matches the metadata.name.

Copy link
Collaborator Author

@jingyih jingyih Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For resource with service generated ID, I am not sure how useful is metadata.name. It will be ignored during GCP resource creation, and later it cannot be used to match (acquire) the GCP resource. To acquire the GCP resource, we have to give GCP API the service generated ID (i.e., via setting spec.resourceID)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean KCC acquire a GCP resource: the BigQuery server creates a Transfer object called "xyz", user then specify KCC metadata.name xyz to acquire that pre-existing resource. Is the service generated ID a valid k8s name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my tests, the generated ID is something like "66e60359-0000-2d33-8bc7-c82add80addc". I think k8s name needs to start and end with an alphanumeric character?

Besides, when user try to acquire a GCP resource, I prefer them to explicitly set spec.ResourceID.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kk, looks like all BigQuery service-generated ID is all using the UUID format. Then I'm good with this.

var id *BigQueryDataTransferConfigIdentity
externalRef := direct.ValueOf(obj.Status.ExternalRef)
if externalRef == "" {
id = BuildID(projectID, location, resourceID)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the problem here is that since we do not assign metadata.name to resourceID, if spec.resourceID is not given and the GCP object is not created (no status.externalRef), this will always pass in an empty resourceID, which fails the following logics.

return nil, fmt.Errorf("BigQueryDataTransferConfig %s/%s has spec.location changed, expect %s, got %s",
u.GetNamespace(), u.GetName(), id.location, location)
}
if id.transferConfigID != resourceID {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this only works for acquire but not KCC-created. Because the transferConfigID is server generated and KCC does not write it back to spec.resourceID (and not metadata.name)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of acquiring this resource, I believe we want users to specifically set spec.resourceID to the service generated ID? (as opposed to set metadata.Name to the service generated ID)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind elaborating a little bit more on why "we want users to specifically set spec.resourceID to the service generated ID"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was referring to
https://screenshot.googleplex.com/6Dcx5KjqfXvuexB

I think it makes sense to have users explicitly set spec.ResourceID to express the intend to "acquire a resource".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, the code is good because the service-generated ID is UUID so it can't be placed in metadata.name

@yuwenma
Copy link
Collaborator

yuwenma commented Sep 13, 2024

I feel like maybe we can merge the tool-generated code first, and handle the service-generated ID in a follow up PR, because the change needs to happen in multiple places and I'd like to use that as a coding example.

@jingyih jingyih force-pushed the BigQueryDataTransferConfig branch 3 times, most recently from 6d549e4 to da9025a Compare September 13, 2024 23:44
@jingyih jingyih changed the title WIP: add SciFi controller for BigQueryDataTransferConfig feat: add SciFi controller for BigQueryDataTransferConfig Sep 13, 2024
@jingyih jingyih force-pushed the BigQueryDataTransferConfig branch from da9025a to 0afa310 Compare September 16, 2024 08:57
@jingyih jingyih force-pushed the BigQueryDataTransferConfig branch from 0afa310 to c3c84d4 Compare September 16, 2024 22:36
@jingyih
Copy link
Collaborator Author

jingyih commented Sep 16, 2024

Rebased to resolve a conflict.

@jingyih jingyih force-pushed the BigQueryDataTransferConfig branch from c3c84d4 to 0f14fe0 Compare September 17, 2024 07:01
Comment on lines 60 to 64
var opts []option.ClientOption
if m.config.UserAgent != "" {
opts = append(opts, option.WithUserAgent(m.config.UserAgent))
}
if m.config.HTTPClient != nil {
opts = append(opts, option.WithHTTPClient(m.config.HTTPClient))
}
if m.config.UserProjectOverride && m.config.BillingProject != "" {
opts = append(opts, option.WithQuotaProject(m.config.BillingProject))
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we have a helper function for this. You can check the controller template

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! update the code.

}

// Get ResourceID
resourceID := direct.ValueOf(obj.Spec.ResourceID)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean KCC acquire a GCP resource: the BigQuery server creates a Transfer object called "xyz", user then specify KCC metadata.name xyz to acquire that pre-existing resource. Is the service generated ID a valid k8s name?

return nil, fmt.Errorf("BigQueryDataTransferConfig %s/%s has spec.location changed, expect %s, got %s",
u.GetNamespace(), u.GetName(), id.location, location)
}
if id.transferConfigID != resourceID {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind elaborating a little bit more on why "we want users to specifically set spec.resourceID to the service generated ID"?

@jingyih jingyih force-pushed the BigQueryDataTransferConfig branch from b8bf4dc to f8daaa5 Compare September 18, 2024 20:35
@yuwenma
Copy link
Collaborator

yuwenma commented Sep 19, 2024

/lgtm
/approve

Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: yuwenma

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-prow google-oss-prow bot merged commit e6d725b into GoogleCloudPlatform:master Sep 19, 2024
16 checks passed
jingyih added a commit to jingyih/k8s-config-connector that referenced this pull request Sep 19, 2024
google-oss-prow bot added a commit that referenced this pull request Sep 19, 2024
@jingyih jingyih changed the title feat: add SciFi controller for BigQueryDataTransferConfig feat: add direct controller for BigQueryDataTransferConfig Sep 27, 2024
nitashadhingra pushed a commit to nitashadhingra/k8s-config-connector that referenced this pull request Oct 10, 2024
@yuwenma yuwenma added this to the 1.124 milestone Oct 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BQ Data Transfer Configs stuck on "Updating"
2 participants