Skip to content
This repository has been archived by the owner on Jun 24, 2020. It is now read-only.

Introduce immutable transforms and consider KnativeServing CR config to be canonical #165

Merged
merged 5 commits into from
Sep 12, 2019

Conversation

jcrossley3
Copy link
Contributor

Fixes #138 and relates to #163

Proposed Changes

@googlebot googlebot added the cla: yes Author(s) signed a CLA. label Sep 11, 2019
Copy link
Contributor

@knative-prow-robot knative-prow-robot left a comment

Choose a reason for hiding this comment

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

@jcrossley3: 2 warnings.

In response to this:

Fixes #138 and relates to #163

Proposed Changes

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

test/e2e_flags.go Outdated Show resolved Hide resolved
test/resources/knativeserving.go Outdated Show resolved Hide resolved
@jcrossley3
Copy link
Contributor Author

/assign @garron

@garron
Copy link
Contributor

garron commented Sep 11, 2019

Thanks @jcrossley3. I also went through this exercise yesterday and put together a similar solution. Given that your review is up, let's run with it. I'm still going to share my branch so that you can take a look at some slightly different options. Namely:

  • It feels like ideally, the Manifestival interface wouldn't reference the Manifest type directly, and Transform would return a Manifestival. It does create some ugliness around getting the Resources because they aren't part of the interface, so I tried to keep the type assertions in code that was type aware. I'm new to go, so I could totally be off in my approach here.

  • I think it might be nice to apply the transforms early in the reconciliation and then make those transformed resources available down the line (e.g. for ensuring deployments are ready). In absence of using the transformed config there, it seems easy to introduce bugs vie new code that assumes it is working with the desired manifest in that function.

I will take a more thorough look through your review to better understand some of the additional changes you made.

// 'metadata.resourceVersion', 'spec.clusterIP', and any existing
// entries in a ConfigMap's 'data' field. So we only overwrite fields
// set in our src resource.
// We need to preserve some target keys, specifically
Copy link
Contributor

Choose a reason for hiding this comment

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

I have a few thoughts/questions here. Maybe it makes sense to split this off into another review so that we can land the state management pieces.

  1. This code is used by anyone who uses this library to apply a manifest. I don't know if there are other consumers of manifestival right now, but it feels a bit unfortunate that implementation decisions about how the operator should work result in functional changes to how this library interprets requests to apply a manifest. Are we sure others are OK with these?

  2. As someone new to manifestival, I was surprised to see this logic and had assumed Apply() behaved similarly to "kubectl apply". Would it make sense to move this to the transform stage? That would make it possible for this library to provide a an opt-in implementation, but would also allow for altering that behavior should it not be right for a particular project. If you think what is here is universally desired behavior, I think it would be worth documenting what the intended behavior is.

  3. While the comments mention a few specific examples where this is necessary, this implementation is generic and applies to all config. Regardless of whether we move it to a transform or not, it's hard for me to conclude from looking at this that the operator's config is going to act as the source of truth once run through this function. Would it be possible/practical to move to a hard-coded list of keys that we want to maintain? That would also serve as a means to ensure we're not breaking important key preservation over time. I'm thinking something like (rough first-pass idea):

    my_manifest.Transform(
        KindFilter("ConfigMap", MaintainExistingValue(my_manifest, ["spec.key1", "spec.key2"]))
    ).ApplyAll()

Copy link
Contributor Author

@jcrossley3 jcrossley3 Sep 11, 2019

Choose a reason for hiding this comment

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

This code has evolved significantly from the PoC it originally was, as has my understanding of operators in general and kubernetes itself. 😄

You're right to assume Apply() behaves similarly to kubectl apply. It should. I would love for it to. I'm waiting for some expert to come along and tell me, "That's dumb, do it like this instead!" Are you that expert? Please!!! 😄

Some of the code in here came from the idea that we should allow external edits to the resources installed by manifestival. I never wanted the operator to overwrite a human's changes. I've come around in my thinking on this. And it's very possible that having the operator be the "source of truth" will simplify this code. That'd be swell.

Right now, to my knowledge, only the serving-operator is using the client-go branch of manifestival. I know of a few other operators based on operator-sdk/controller-runtime that use the master branch without a problem, so I'm sensitive to releasing breaking changes, but not opposed to it as long as we're clear about what changes and why.

Personally, I hate the UpdateChanged function -- it's gone through quite a few iterations and has some fairly comprehensive tests around it because of its brittleness. I'm always open to improving it, or better yet, eliminating it!

Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately, I am far from your expert on kubectl apply. From looking through more of the apply docs, I do see that it has it's own merging, so this may be closer to the kubectl apply behavior than I had realized.

Regardless, it does seem like the merging is going to pose a challenge in making the operator's spec the source of truth. We can tackle that elsewhere though. I don't think you should block your review on this feedback.

After creating the KnativeServing instance, we then update it twice,
once with an entry for the config-logging ConfigMap and then again
without the key, verifying that the operator correctly syncs the
ConfigMap each time.
This relies on the Transform function now being immutable, returning a
new Manifest instead of mutating its source resources.

This is related to knative#163 as well.
@jcrossley3
Copy link
Contributor Author

  • I think it might be nice to apply the transforms early in the reconciliation and then make those transformed resources available down the line (e.g. for ensuring deployments are ready). In absence of using the transformed config there, it seems easy to introduce bugs vie new code that assumes it is working with the desired manifest in that function.

Good idea, @garron -- done.

Copy link
Contributor

@garron garron left a comment

Choose a reason for hiding this comment

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

Looks great, thanks!

test/resources/knativeserving.go Outdated Show resolved Hide resolved
@knative-prow-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: garron, jcrossley3

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

This also makes the WaitForConfigMap helper more helpful
@garron
Copy link
Contributor

garron commented Sep 12, 2019

/lgtm

@knative-prow-robot knative-prow-robot merged commit 90a7c7e into knative:master Sep 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Deleting a KnativeServing CR with changes, and then reapplying blank KS CR should use default serving yaml
4 participants