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

Fixes extra newline from confs #557

Conversation

auniyal61
Copy link

As we are using templates to dynamicaly create confs on conditions, Often extra newlines are getting added in confs, we should remove them.

@stuggi
Copy link
Contributor

stuggi commented Sep 4, 2024

This seems to be not correct for e.g. this case https://go.dev/play/p/5ms4rPxaX0l where you have 2 new lines:

line 1
line 2


line 3

it would result in

line 1
line 2line 3

Can you explain what you try to achieve? Do you want to replace any empty line from the resulting rendered template?

FYI, a commit to fix the govet was just merged. you'd have to rebase.

Copy link
Contributor

@gibizer gibizer left a comment

Choose a reason for hiding this comment

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

@stuggi How would you feel about adding a post processing hook (a function parameter) to the untils.Template so the service operators can implement any kind of post processing after the template is rendered? Would it be too much complexity?

modules/common/util/template_util.go Outdated Show resolved Hide resolved
@stuggi
Copy link
Contributor

stuggi commented Sep 4, 2024

could you explain the motivation of doing it as a separate task, instead of updating the template to suppress new lines https://pkg.go.dev/text/template#hdr-Text_and_spaces / https://docs.gomplate.ca/syntax/#suppressing-leading-newlines ?

@auniyal61
Copy link
Author

it would result in

line 1
line 2line 3

so initially when I tested it with nova-operator, I decided to go with below because we need atleast 2 lines for new section.
s = strings.ReplaceAll(s, "\n\n\n", "\n")
missed '\n' here, as I tested with sample conf.file adding at https://github.com/openstack-k8s-operators/lib-common/tree/main/modules/common/util/testdata/templates/testservice/config

could you explain the motivation of doing it as a separate task, instead of updating the template to suppress new lines https://pkg.go.dev/text/template#hdr-Text_and_spaces / https://docs.gomplate.ca/syntax/#suppressing-leading-newlines ?

we tried that here openstack-k8s-operators/nova-operator#842

but it seems confusing, also conf did not rendered properly.
so added here, so this can reflect on all conf files.

@SeanMooney
Copy link
Contributor

could you explain the motivation of doing it as a separate task, instead of updating the template to suppress new lines https://pkg.go.dev/text/template#hdr-Text_and_spaces / https://docs.gomplate.ca/syntax/#suppressing-leading-newlines ?

yes so we have looked at doing that twice
amit ahs a draft and it is very messy and makes the template harder to read.

openstack-k8s-operators/nova-operator#855

I did a POC of that about 18 months ago when we were refactoring our templates
and abandoned it for the same reason

the current apporch is not correct.

i would personnly do this in a streaming fashion.
scan the rendered template line by line and skip newlines if the previous line was a new line
so i would not use replace or similar regex approaches

i like the idea of being able to pass a object via an interface to the function but
if we take that approach i think a simple line striping functor object should be added to lib common since i suspect that will be what people normally want.

we could do this in the nova operator today but we wanted to do it in lib common to benefit all the operators

at the end of the day this is a cosmetic enhancement but its sill nice to have for readablity

@stuggi
Copy link
Contributor

stuggi commented Sep 4, 2024

ack, thanks for the explanation. doing this in the template can be confusing. I am ok to add it as a post processing, but I think it should be optional so that we keep the current behavior as the default and one needs to enable it if they like.

@SeanMooney
Copy link
Contributor

auniyal61 added a commit to auniyal61/nova-operator that referenced this pull request Sep 4, 2024
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from 9bde700 to 14cb785 Compare September 9, 2024 08:43
auniyal61 added a commit to auniyal61/nova-operator that referenced this pull request Sep 9, 2024
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from b322894 to 14cb785 Compare September 9, 2024 09:33
auniyal61 added a commit to auniyal61/nova-operator that referenced this pull request Sep 9, 2024
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from 14cb785 to b9d5ea7 Compare September 9, 2024 10:22
auniyal61 added a commit to auniyal61/nova-operator that referenced this pull request Sep 9, 2024
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from b9d5ea7 to 7a129ce Compare September 10, 2024 08:25
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch 2 times, most recently from 8e3657e to 8dec8d8 Compare September 11, 2024 20:57
auniyal61 added a commit to auniyal61/nova-operator that referenced this pull request Sep 11, 2024
Opting to remove extra lines from nova confs

Depends-On: openstack-k8s-operators/lib-common#557
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from 8dec8d8 to 6043e80 Compare September 11, 2024 21:36
auniyal61 added a commit to auniyal61/nova-operator that referenced this pull request Sep 11, 2024
Opting to remove extra lines from nova confs

Depends-On: openstack-k8s-operators/lib-common#557
As we are using templates to dynamicaly create confs on conditions,
Often extra newlines are getting added in confs, we should remove them.
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from a5120b6 to b5023a9 Compare September 13, 2024 13:03
@gibizer
Copy link
Contributor

gibizer commented Sep 16, 2024

I've pushed an extra commit to the branch with unit test for the cleaning logic and that shows some inconcistencies around the empty line handling between sections.

modules/common/util/template_util.go Show resolved Hide resolved
@@ -57,6 +57,48 @@ type Template struct {
ConfigOptions map[string]interface{} // map of parameters as input data to render the templates
SkipSetOwner bool // skip setting ownership on the associated configmap
Version string // optional version string to separate templates inside the InstanceType/Type directory. E.g. placementapi/config/18.0
PostProcessCleanup bool // optional boolean parameter to remove extra new lines from service confs, by default set to false
Copy link
Contributor

Choose a reason for hiding this comment

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

I still prefer passing in the function references to run as post processing as that allows for a lot more flexibility in the future.

But if the others wants a separate boolean for each future post processing then at least be super specific what this boolean enables. The code Sean provided not just remove extra empty lines from the rendered template but also insert missing empty lines between ini like sections.

Copy link
Contributor

Choose a reason for hiding this comment

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

We had a call with @auniyal61 and I learned that a single Template instance can actually mean a list of rendered files. Both via AdditionalTemplate and the logic that picks up a set of files from a path + glob. This means that a single PostProcessCleanup bool is actually applied not to a single file but to a set of diverse files(potentially a mix of different file types like ini, kolla json, apache conf). This would also be true for the set of functions as well if we change this to that type. This makes the situation more complicated as post processing cannot be configured per template file. Changing the Template to allow per file post processing is seems to be a big work so I drop the idea out of the scope of this change.

@stuggi How do you feel about eventually refactoring Template? I see three possible directions we could go

  1. keep a single Template struct to pick up multiple files and render them as today, and then extend the interface to make such rendering still configurable per template file level
  2. break the coupling between template rendering and Secret / CM creation with the rendered template. Make it two separate, client callable, steps. Like below to allow post processing on the client side.
    renderedTemplates = utils.RenderTemplate(template utils.Template)
    // the service operator can do post processing here on the client side
    utils.CreateCM/Secret(renderedTemplates)
    
  3. break the current Template struct to have a list of Template structs one for each template file making the template rendering configuration per template file struct.

Copy link
Author

Choose a reason for hiding this comment

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

Hi @stuggi , can you please suggest on this.

Copy link
Contributor

Choose a reason for hiding this comment

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

@auniyal61 sorry for the delay. I was out last week. I'll get back to this asap.

Copy link
Contributor

@stuggi stuggi Oct 11, 2024

Choose a reason for hiding this comment

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

@gibizer @SeanMooney @auniyal61 sorry for the delay, I finally had some time today to look into this. What you think about this approach [1]. This adds new template functions , especially for our use case here execTempl and removeNewLines. With this you can define your template inline and then render the template using the execTempl and remove multiple empty lines using removeNewLines. An example on how you could use that in a template is shown in the description.

Specific for the nova.conf in this example PR [2]. The benefit is that you could control this just from inside the template and no other code change is required.

[1] #569
[2] openstack-k8s-operators/nova-operator#874

@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch 2 times, most recently from 6f49beb to 8e61242 Compare September 17, 2024 07:21
@auniyal61 auniyal61 force-pushed the remove-extra-newlines-from-confs branch from 8e61242 to a7150d4 Compare September 17, 2024 07:29
SkipSetOwner bool // skip setting ownership on the associated configmap
Version string // optional version string to separate templates inside the InstanceType/Type directory. E.g. placementapi/config/18.0
PostProcessConfFilesCleanup bool // optional boolean parameter to remove extra new lines from service confs, by default set to false
}
Copy link
Contributor

Choose a reason for hiding this comment

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

so we could likely proceed with this version for now

however how i would approach this is as follows

1 defince a new interface with one function which is takes a string and returns a string to post_process the rendered file.

instead of adding a bool here we would add a map of file exteion to interface object

then we would loop over all the files in the template and if there is registered post processor for that exteion in the map we can apply it to that specific file

we could also have a sentenal value for a default handleler if we want but i think that is likely not needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess that is close to my suggestion/question 1 above. #557 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

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

by hte way the key could be a regex instead of an extnetion allowing mapping the handler to either a file or set of files.

this would just be applied to the keys for the config map/serecte but that might be overkill.

its simple to do and reason about however so we might just want to do it now

Copy link
Contributor

Choose a reason for hiding this comment

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

yep more or less

i think breaking up the templates and configmap logic ectra will be a lot more work

we can do that eventually but for now i think this would be a minimal change to the existing proposal that we can extend with minimal impact on other operators

and in the future if we want to do that larger refactor for 2/3 we still can

i would do that by introducing a new Struct by the way and keeping but deprecating the current one so we can avoid a hard switch over.

so for the short term i would vote for 1 and then see if we need to do 2/3 later

@auniyal61
Copy link
Author

closing in favor of #569

@auniyal61 auniyal61 closed this Oct 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants