diff --git a/internal/pkg/rpaas/nginx/configuration_render.go b/internal/pkg/rpaas/nginx/configuration_render.go index 868a762bb..409cd2530 100644 --- a/internal/pkg/rpaas/nginx/configuration_render.go +++ b/internal/pkg/rpaas/nginx/configuration_render.go @@ -21,6 +21,8 @@ import ( ) var trimTrailingSpacesRegex = regexp.MustCompile(`[ \t]+?\n`) +var nginxTemplate = &template.Template{} +var errRenderInnerTemplate = fmt.Errorf("template contains renderInnerTemplate") type ConfigurationRenderer interface { Render(ConfigurationData) (string, error) @@ -58,39 +60,50 @@ func (r *rpaasConfigurationRenderer) Render(c ConfigurationData) (string, error) } func NewConfigurationRenderer(cb ConfigurationBlocks) (ConfigurationRenderer, error) { - tpl, err := defaultMainTemplate.Clone() + var err error + nginxTemplate, err = defaultMainTemplate.Clone() if err != nil { return nil, err } if cb.MainBlock != "" { - tpl, err = template.New("main").Funcs(templateFuncs).Parse(cb.MainBlock) + nginxTemplate, err = template.New("main").Funcs(templateFuncs).Parse(cb.MainBlock) if err != nil { return nil, err } } - if _, err = tpl.New("root").Parse(cb.RootBlock); err != nil { + if _, err = nginxTemplate.New("root").Parse(cb.RootBlock); err != nil { return nil, err } - if _, err = tpl.New("http").Parse(cb.HttpBlock); err != nil { + if _, err = nginxTemplate.New("http").Parse(cb.HttpBlock); err != nil { return nil, err } - if _, err = tpl.New("server").Parse(cb.ServerBlock); err != nil { + if _, err = nginxTemplate.New("server").Parse(cb.ServerBlock); err != nil { return nil, err } - if _, err = tpl.New("lua-server").Parse(cb.LuaServerBlock); err != nil { + if _, err = nginxTemplate.New("lua-server").Parse(cb.LuaServerBlock); err != nil { return nil, err } - if _, err = tpl.New("lua-worker").Parse(cb.LuaWorkerBlock); err != nil { + if _, err = nginxTemplate.New("lua-worker").Parse(cb.LuaWorkerBlock); err != nil { return nil, err } - return &rpaasConfigurationRenderer{t: tpl}, nil + return &rpaasConfigurationRenderer{t: nginxTemplate}, nil +} + +func renderInnerTemplate(name string, nginx ConfigurationData) (string, error) { + tpl := nginxTemplate.Lookup(name) + parsedTemplate := tpl.Tree.Root.String() + if strings.Contains(parsedTemplate, "renderInnerTemplate") { + return "", errRenderInnerTemplate + } + r := &rpaasConfigurationRenderer{t: tpl} + return r.Render(nginx) } func buildLocationKey(prefix, path string) string { @@ -232,6 +245,7 @@ func defaultCertificate(instance *v1alpha1.RpaasInstance) *nginxv1alpha1.NginxTL } var internalTemplateFuncs = template.FuncMap(map[string]interface{}{ + "renderInnerTemplate": renderInnerTemplate, "boolValue": v1alpha1.BoolValue, "buildLocationKey": buildLocationKey, "hasRootPath": hasRootPath, @@ -282,6 +296,7 @@ var rawNginxConfiguration = ` {{- $all := . -}} {{- $config := .Config -}} {{- $instance := .Instance -}} +{{- $httpBlock := renderInnerTemplate "http" . -}} # This file was generated by RPaaS (https://github.com/tsuru/rpaas-operator.git) # Do not modify this file, any change will be lost. @@ -437,7 +452,7 @@ http { {{ template "lua-worker" . }} } - {{ template "http" . }} + {{ $httpBlock }} server { listen {{ managePort $instance }}; diff --git a/internal/pkg/rpaas/nginx/configuration_render_test.go b/internal/pkg/rpaas/nginx/configuration_render_test.go index c80c1cee2..839d7fa36 100644 --- a/internal/pkg/rpaas/nginx/configuration_render_test.go +++ b/internal/pkg/rpaas/nginx/configuration_render_test.go @@ -21,10 +21,11 @@ func TestRpaasConfigurationRenderer_Render(t *testing.T) { size300MB := resource.MustParse("300Mi") tests := []struct { - name string - blocks ConfigurationBlocks - data ConfigurationData - assertion func(*testing.T, string) + name string + blocks ConfigurationBlocks + data ConfigurationData + assertion func(*testing.T, string) + expectedError string }{ { name: "with false values", @@ -271,6 +272,21 @@ func TestRpaasConfigurationRenderer_Render(t *testing.T) { assert.Regexp(t, `\s# some custom conf at init_worker_by_lua_block context`, result) }, }, + { + name: "with invalid recursive renderInnnerTemplate inside config blocks", + blocks: ConfigurationBlocks{ + RootBlock: `# some custom conf at {{ "root" }} context`, + HttpBlock: "# some custom conf at {{ $var := renderInnerTemplate \"http\" .}} context", + ServerBlock: "# some custom conf at server context", + LuaServerBlock: "# some custom conf at init_by_lua_block context", + LuaWorkerBlock: "# some custom conf at init_worker_by_lua_block context", + }, + data: ConfigurationData{ + Config: &v1alpha1.NginxConfig{}, + Instance: &v1alpha1.RpaasInstance{}, + }, + expectedError: errRenderInnerTemplate.Error(), + }, { name: "with app bound", data: ConfigurationData{ @@ -602,6 +618,10 @@ func TestRpaasConfigurationRenderer_Render(t *testing.T) { cr, err := NewConfigurationRenderer(tt.blocks) require.NoError(t, err) result, err := cr.Render(tt.data) + if tt.expectedError != "" { + assert.ErrorContains(t, err, tt.expectedError) + return + } require.NoError(t, err) tt.assertion(t, result) })