Skip to content
Open
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
59 changes: 59 additions & 0 deletions pkg/operator/resource/resourceapply/apiextensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,39 @@ import (
"k8s.io/klog/v2"
)

// ApplyCustomResourceDefinitionV1Improved applies the required CustomResourceDefinition to the cluster, preserving an injected ca bundle.
func ApplyCustomResourceDefinitionV1Improved(ctx context.Context, client apiextclientv1.CustomResourceDefinitionsGetter, recorder events.Recorder, required *apiextensionsv1.CustomResourceDefinition) (*apiextensionsv1.CustomResourceDefinition, bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please double-check but I think that the *Improved versions let callers reuse a cache to avoid unnecessary writes when nothing has changed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please also add a unit test

existing, err := client.CustomResourceDefinitions().Get(ctx, required.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
requiredCopy := required.DeepCopy()
actual, err := client.CustomResourceDefinitions().Create(
ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*apiextensionsv1.CustomResourceDefinition), metav1.CreateOptions{})
resourcehelper.ReportCreateEvent(recorder, required, err)
return actual, true, err
}
if err != nil {
return nil, false, err
}

modified := false
existingCopy := existing.DeepCopy()

copyCustomResourceDefinitionConversionWebhookCABundle(existing, required)
Copy link
Contributor

Choose a reason for hiding this comment

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

you pass the original pointer to the required obj which is modified. you need to make a copy of that obj and pass the pointer to the copy

resourcemerge.EnsureCustomResourceDefinitionV1(&modified, existingCopy, *required)
if !modified {
return existing, false, nil
}

if klog.V(2).Enabled() {
Copy link
Contributor

Choose a reason for hiding this comment

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

why not to use klog.V(2).Infof(...) ?

klog.Infof("CustomResourceDefinition %q changes: %s", existing.Name, JSONPatchNoError(existing, existingCopy))
}

actual, err := client.CustomResourceDefinitions().Update(ctx, existingCopy, metav1.UpdateOptions{})
resourcehelper.ReportUpdateEvent(recorder, required, err)

return actual, true, err
}

// ApplyCustomResourceDefinitionV1 applies the required CustomResourceDefinition to the cluster.
func ApplyCustomResourceDefinitionV1(ctx context.Context, client apiextclientv1.CustomResourceDefinitionsGetter, recorder events.Recorder, required *apiextensionsv1.CustomResourceDefinition) (*apiextensionsv1.CustomResourceDefinition, bool, error) {
existing, err := client.CustomResourceDefinitions().Get(ctx, required.Name, metav1.GetOptions{})
Expand Down Expand Up @@ -55,3 +88,29 @@ func DeleteCustomResourceDefinitionV1(ctx context.Context, client apiextclientv1
resourcehelper.ReportDeleteEvent(recorder, required, err)
return nil, true, nil
}

// copyCustomResourceDefinitionConversionWebhookCABundle populates spec.conversion.webhook.clientConfig.caBundle fields from
// existing resource if it was set before and is not set in present. This provides upgrade compatibility with service-ca-bundle operator.
Copy link
Contributor

Choose a reason for hiding this comment

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

since this function provides upgrade compatibility with service-ca-bundle operator why shouldn't the ApplyCustomResourceDefinitionV1 receive this improvement ?

Copy link
Author

Choose a reason for hiding this comment

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

I thought about creating a separate function to not "surprisingly" change behavior of the existing function.

I'm okay with doing the adjustment to ApplyCustomResourceDefinitionV1

Copy link
Member

Choose a reason for hiding this comment

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

I think creating an "Improved" function has generally been the approach around here right?
To not surprise importers with a "breaking change" in behaviour.
That said if we think we are ok with that, +1

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that the *Improved versions also let callers reuse a cache to avoid unnecessary writes when nothing has changed. Usually by accepting the cache ResourceCache param.

I'm ok with a new function but I think the new function should also take the cache ResourceCache param.

We should also consider deprecating the old function. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Sounds reasonable thanks

func copyCustomResourceDefinitionConversionWebhookCABundle(existing *apiextensionsv1.CustomResourceDefinition, required *apiextensionsv1.CustomResourceDefinition) {
Copy link
Contributor

Choose a reason for hiding this comment

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

could you rename the params to from and to ? it would be easier to read the code.

// Skip in case the required resource does not have a webhook configured.
if required.Spec.Conversion == nil || required.Spec.Conversion.Webhook == nil || required.Spec.Conversion.Webhook.ClientConfig == nil {
return
}

// Skip in case the required resource does not have a webhook configured with a strategy of WebhookConverter.
if required.Spec.Conversion.Strategy != apiextensionsv1.WebhookConverter {
return
}

// Skip in case the required resource has a webhook configured with its own ca bundle.
if required.Spec.Conversion.Webhook.ClientConfig.CABundle != nil {
return
}

// Skip in case the existing resource does not have a ca bundle set.
if existing.Spec.Conversion == nil || existing.Spec.Conversion.Webhook == nil || existing.Spec.Conversion.Webhook.ClientConfig == nil || existing.Spec.Conversion.Webhook.ClientConfig.CABundle == nil {
return
}

required.Spec.Conversion.Webhook.ClientConfig.CABundle = existing.Spec.Conversion.Webhook.ClientConfig.CABundle
}