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 support for templating in configs #6251

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

Conversation

robholland
Copy link
Contributor

What changed?

Support for text/template was added to the config loading system. Sprig is used for some useful templating functions, as used by dockerize and helm.

Why?

This avoids the need to use dockerize to render config templates when deploying in containers. Without the need to write the intermediate config to disk, the image can be immutable. Any volumes used to copy over an alternative template can be read-only also, enabling more secure deployment.

How did you test it?

Built a FROM scratch image using the updated temporal-server binary and confirmed that it would work when deployed using (slightly adjusted) version of our helm charts.

Potential risks

There is a very slim chance that some configuration files might accidentally have some text that looks like go template, which the code would now try and interpret. This seems very unlikely.

Documentation

Documentation should be updated to explain this new feature, but given it's so close to the standard deployment setup with dockerize, this doesn't need to block release of the feature imho.

Is hotfix candidate?

No

Amongst other use cases, this avoids the need to use dockerize in container
deployments, making it much easier to build more secure images which do not
need write access to the filesystem.
@robholland robholland requested a review from a team as a code owner July 8, 2024 13:24
@robholland
Copy link
Contributor Author

If preferred to avoid the slight risk we can add a flag that enables templating.

Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

I wonder how many people use the templates outside of our docker compose setup to justify putting this dependency and additional functionality in the code.

Also wondering if this would break if users store templates in their config files, not sure there's a use case for that.

@bergundy bergundy closed this Jul 15, 2024
@bergundy bergundy reopened this Jul 15, 2024
@robholland
Copy link
Contributor Author

I misremembered during our call. Our kubernetes (including Helm) installs also need this functionality, its required to make use of passwords stored in kubernetes secrets.

Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

Considering we need this templating in all of the container based deployment setups, and this allows images to be immutable, I'm fine with this approach.

I think server configs might need an overhaul though, ideally we wouldn't require multiple files and can simplify some of the structure. That's a bigger effort and we'd need to think about it some more.

for _, f := range files {
// This is tagged nosec because the file names being read are for config files that are not user supplied
// #nosec
data, err := os.ReadFile(f)
if err != nil {
return err
}
err = yaml.Unmarshal(data, config)

tpl, err := template.New("config").Funcs(templateFuncs).Parse(string(data))
Copy link
Member

Choose a reason for hiding this comment

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

is this compatible with the existing config_template.yaml? it looks like sprig provides a function used like env "VAR" but the template is written with things like .Env.VAR. do we have to migrate the template?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The template would need adjusting. Sprig's default argument ordering is reversed from the dockerize version. There are probably a few other gotchas. I would suggest leaving the existing template as it is and creating a new template under config/docker.yaml with the updated syntax so that containers using dockerize will continue to work until we deprecate that. Newer containers can use this new functionality with the updated config file. I'll add a working config file to this PR.

Takes the opportunity to simplify the template a little and add some errors for common issues.
@robholland robholland requested a review from dnr August 12, 2024 14:49
@alexshtin alexshtin changed the title Add support for templating in configs. Add support for templating in configs Aug 12, 2024
return err
}

err = yaml.Unmarshal(rendered.Bytes(), config)
Copy link
Member

Choose a reason for hiding this comment

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

It also would be very useful for debugging purpose to check what is in rendered. And not only in case of template error. Template syntax might be fine, but produce different output. Write it to stdout? I am ok, if you do it in separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed to put this into a tdbg command for now, and later move into the server binary once we're happy (due to backwards compat requirements).

@dnr
Copy link
Member

dnr commented Aug 20, 2024

If preferred to avoid the slight risk we can add a flag that enables templating.

Another simple approach would be to look for a string like enable-builtin-templating in the first 100 chars of the file (it would be in a comment).

I think server configs might need an overhaul though, ideally we wouldn't require multiple files and can simplify some of the structure.

What multiple files do you mean? Only one static config file is required. Dynamic config requires a second file only if you want to change anything from defaults, but it would be simple to add a "static dynamic config" section in the static config file if you wanted to override some things but not actually have them be dynamic.

Copy link
Member

@dnr dnr left a comment

Choose a reason for hiding this comment

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

I'm fine with this. I don't like the extra dependency but if it lets us get rid of dockerize that's nice.

I have a little concern about the two copies of the config getting out of sync, but it's changed pretty rarely and we should be able to deprecate the other one soon, right?

@bergundy
Copy link
Member

What multiple files do you mean? Only one static config file is required. Dynamic config requires a second file only if you want to change anything from defaults, but it would be simple to add a "static dynamic config" section in the static config file if you wanted to override some things but not actually have them be dynamic.

Yeah, it's less about requiring multiple files but that multiple files are supported and there's a concept of an environment that's not ideal to expose in the interface IMHO.
It would have been nice to also support dynamic configs in the same file though. My main concern is experience in the dev server and we've deliberately decided not to support server configs because they don't have good DX today.

@dnr
Copy link
Member

dnr commented Sep 26, 2024

Yeah, it's less about requiring multiple files but that multiple files are supported and there's a concept of an environment that's not ideal to expose in the interface IMHO. It would have been nice to also support dynamic configs in the same file though. My main concern is experience in the dev server and we've deliberately decided not to support server configs because they don't have good DX today.

Oh, yeah, the environment stuff should go, agreed.

Supporting embedding dynamic config in the static config file would be like 20 lines of code. It would be a pretty easy change to even make it dynamic too. Is there a proposal for what the specific UX should be? I can whip up something but maybe it's better to design it first.

@bergundy
Copy link
Member

Yeah, it's less about requiring multiple files but that multiple files are supported and there's a concept of an environment that's not ideal to expose in the interface IMHO. It would have been nice to also support dynamic configs in the same file though. My main concern is experience in the dev server and we've deliberately decided not to support server configs because they don't have good DX today.

Oh, yeah, the environment stuff should go, agreed.

Supporting embedding dynamic config in the static config file would be like 20 lines of code. It would be a pretty easy change to even make it dynamic too. Is there a proposal for what the specific UX should be? I can whip up something but maybe it's better to design it first.

Off the top of my head, to improve DX, we need to accept a single file, drop the directory and environment concept and allow embedding dynamic config in this single file. We'd better design this though before making changes, this will require some thought to be done in a non disruptive way.

@bergundy
Copy link
Member

@dnr #6561

@robholland
Copy link
Contributor Author

I've added a comment that enables the templating, and a tdbg command to render the template (as YAML and Config{}) for debugging.

common/config/loader.go Outdated Show resolved Hide resolved
common/config/loader.go Outdated Show resolved Hide resolved
func newConfigCommands() []*cli.Command {
return []*cli.Command{
{
Name: "render",
Copy link
Member

Choose a reason for hiding this comment

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

Why not just add a render-config command to the server binary itself? It's a trivial amount of code, and then you don't need to duplicate anything into tdbg (which is admittedly also trivial). As a side-effect it'll better replicate the file lookup that the server does, which can be confusing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree about the file paths being a bonus, but also it seems helpful to be able to point the command at a config file which isn't (yet) in the right place, for testing. So I'd want to be able to over-ride the path if we did move this over to temporal.

Copy link
Member

Choose a reason for hiding this comment

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

There should definitely be a way to point the server to a single file, the env/zone stuff is confusing. That's what #6561 is about.

It seems like it may not be that helpful, though, since the config will depend on a lot of env vars, so it'd be easiest to run it with docker or k8s anyway to get an interesting result. In that case the config will already be in the right place and the easiest thing would be to override the subcommand from start to render-config?

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