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

Add a WithValueTranslator option to Reconciller. #114

Merged

Conversation

porridge
Copy link
Member

@porridge porridge commented Nov 9, 2021

A Translator is a way to produces helm values based on the fetched custom
resource itself (unlike Mapper which can only see Values).

This way the code which converts the custom resource to Helm values can first
convert an Unstructured into a regular struct, and then rely on Go type
safety rather than work with a tree of maps from string to interface{}.

Thanks to having access to a Context, the code can also safely access the
network, for example in order to retrieve other resources from the k8s cluster,
when they are referenced by the custom resource.

Fixes: #113

Copy link
Member Author

@porridge porridge left a comment

Choose a reason for hiding this comment

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

)

// TODO: Consider deprecating Mapper and overrides in favour of Translator.
Copy link
Member Author

Choose a reason for hiding this comment

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

Please let me know what do you think about this. Since Translator is a strictly more powerful interface, perhaps we should get rid of Mapper?

Copy link
Member

@joelanford joelanford Nov 18, 2021

Choose a reason for hiding this comment

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

+1 from me for getting rid of Mapper (pending a conversation about the timing of applying overrides)

@coveralls
Copy link

coveralls commented Nov 9, 2021

Pull Request Test Coverage Report for Build 1530128681

  • 33 of 33 (100.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.2%) to 62.149%

Totals Coverage Status
Change from base Build 1476478121: 0.2%
Covered Lines: 1683
Relevant Lines: 2708

💛 - Coveralls

if err := crVals.ApplyOverrides(r.overrideValues); err != nil {
return chartutil.Values{}, err
}
vals := r.valueMapper.Map(crVals.Map())
vals = r.valueMapper.Map(crVals.Map())
Copy link
Member

Choose a reason for hiding this comment

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

agreed, having valueMapper is not of much use here. Instead of using both valueTranslator and valueMapper on the same values can we prioritize the translatorfunc if its not nil by the user?

Copy link
Member Author

Choose a reason for hiding this comment

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

@varshaprasad96 can you please clarify what you mean by "prioritize the translatorfunc if its not nil by the user"?
Do you mean passing both WithValueMapper and WithValueTranslator to New() should be rejected?

Copy link
Member

@varshaprasad96 varshaprasad96 Nov 12, 2021

Choose a reason for hiding this comment

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

If Translator is passed, we can ignore the mapper (in case both are non-nil) instead of applying both. This would make it easier to deprecate and remove mapper completely later. This is just so that we don't have a breaking change immediately. Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm afraid it would be detrimental to developer experience if the WithValueMapper option was silently ignored when the WithValueTranslator option would be passed. IMHO it would violate the principle of least astonishment.

Copy link
Member

@varshaprasad96 varshaprasad96 Nov 15, 2021

Choose a reason for hiding this comment

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

Completely agree. I had logging a warning and docs along with it in mind so that we don't have to make a breaking change of removing WithValueMapper immediately. It would be nice to discuss the PR in tomorrow's community meeting. This is a really helpful addition, would definetely want to have this PR merged soon :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately I'll be in a place with poor network coverage at that time so I will not be able to join the meeting. But to summarise my thoughts:

  • I don't think we need to remove value mappers in this PR, or even the same release, but it would make sense to add deprecation warnings to prepare for removal if we want to do it eventually,
  • a warning and docs alone are in my experience insufficient countermeasure to a surprise in the API unless there is no other option, and I think we have a good alternative:
  • IF we want to make mappers and translators exclusive, then I'd strongly recommend returning and error from New in case both WithValueMapper and WithValueTranslator are passed. This is not going to harm existing users, unless they try using a translator, in which case such error is a useful hint.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hi, any updates on this after the meeting? How do we proceed on this?

Also, would it be possible to add me to the operator-framework org? Just so that I can configure GitHub to send PR notifications to my work email..

@joelanford
Copy link
Member

There's a similar PR to this one (#93).

I mostly summarized my thoughts on this subject here.

My main area of concern is the timing of applying value overrides:

One notable semantic change would be that all of the translation and mapping would happen before overrides are applied. This would make setting the overrides less ergonomic since mapped values may otherwise be an internal implementation detail of the operator.

If a translator is in use, someone configuring overrides will need to be aware of how the CR is mapped to chart values because the overrides apply to the translator's output. This means potentially exposing internal chart implementation details to users applying overrides at runtime.

@porridge
Copy link
Member Author

Thanks for pointing me at the overrides documentation, @joelanford - I guess I didn't really understand its purpose before.
Here's my stab at applying overrides first. PTAL

Rebased to take advantage of #112 but otherwise the first commit should be unchanged.

pkg/reconciler/internal/values/values_test.go Outdated Show resolved Hide resolved
pkg/reconciler/reconciler.go Outdated Show resolved Hide resolved
Comment on lines 25 to 26
// TODO: Consider deprecating Mapper in favour of Translator.

Copy link
Member

Choose a reason for hiding this comment

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

Let's go ahead and deprecate it IMO.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

crVals, err := internalvalues.FromUnstructured(obj)
if err != nil {
func (r *Reconciler) getValues(ctx context.Context, obj *unstructured.Unstructured) (chartutil.Values, error) {
if err := internalvalues.ApplyOverrides(r.overrideValues, obj); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

👍 This looks great!

A Translator is a way to produces helm values based on the fetched custom
resource itself (unlike `Mapper` which can only see `Values`).

This way the code which converts the custom resource to Helm values can first
convert an `Unstructured` into a regular struct, and then rely on Go type
safety rather than work with a tree of maps from `string` to `interface{}`.

Thanks to having access to a `Context`, the code can also safely access the
network, for example in order to retrieve other resources from the k8s cluster,
when they are referenced by the custom resource.
@porridge
Copy link
Member Author

porridge commented Dec 2, 2021

Applied the suggestions and squashed the commits.
I also tried to improve the docstrings a little and make sure they look sane in godoc.
Also added a nolint pragma for the use of Mapper to make our lint pass.
PTAL @joelanford

Copy link
Member

@joelanford joelanford left a comment

Choose a reason for hiding this comment

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

/approve

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.

Allow more flexibility in the code which converts CR to Helm values
4 participants