<p>I am creating an Helm Chart and I am having problems when it comes to importing files:</p>
<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: vcl-template
  namespace: {{.Release.Namespace}}
data:
    {{- (.Files.Glob &quot;config/varnish/default.vcl.tmpl&quot;).AsConfig | nindent 2 }}
    {{- (.Files.Glob &quot;config/varnish/nginx.conf&quot;).AsConfig | nindent 2 }}
</code></pre>
<p>This imports the file <code>config/varnish/nginx.conf</code> just fine but the file <code>config/varnish/default.vcl.tmpl</code> is imported with <code>\n</code> instead of newlines, so the data on the ConfigMap gets all buggy:</p>
<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: vcl-template
  namespace: default
data:
  default.vcl.tmpl: &quot;vcl 4.0;\n\nimport std;\nimport directors;\n\n{{ range .Frontends
    }}\nbackend {{ .Name }} {\n    .host = \&quot;{{ .Host }}\&quot;;\n    .port = \&quot;{{ .Port
    }}\&quot;;\n}\n{{- end }}\n\n{{ range .Backends }}\nbackend be-{{ .Name }} {\n    .host
    = \&quot;{{ .Host }}\&quot;;\n    .port = \&quot;{{ .Port }}\&quot;;\n}\n{{- end }}\n\nacl purge {\n
    \   \&quot;127.0.0.1\&quot;;\n    \&quot;localhost\&quot;;\n    \&quot;::1\&quot;;\n    {{- range .Frontends }}\n
    \   \&quot;{{ .Host }}\&quot;;\n    {{- end }}\n    {{- range .Backends }}\n    \&quot;{{ .Host
    }}\&quot;;\n    {{- end }}\n}\n\nsub vcl_init {\n    new cluster = directors.hash();\n\n
    \   {{ range .Frontends -}}\n    cluster.add_backend({{ .Name }}, 1);\n    {{ end
    }}\n\n    new lb = directors.round_robin();\n\n    {{ range .Backends -}}\n    lb.add_backend(be-{{
    .Name }});\n    {{ end }}\n}\n\nsub vcl_recv {\n\n    unset req.http.x-cache;\n
    \   set req.backend_hint = cluster.backend(req.url);\n    set req.http.x-shard =
    req.backend_hint;\n    if (req.http.x-shard != server.identity) {\n        return(pass);\n
    \   }\n    set req.backend_hint = lb.backend();\n\n    if (req.method == \&quot;PURGE\&quot;)
    {\n        if (client.ip !~ purge) {\n            return (synth(405, \&quot;Method not
    allowed\&quot;));\n        }\n        # To use the X-Pool header for purging varnish
    during automated deployments, make sure the X-Pool header\n        # has been added
    to the response in your backend server config. This is used, for example, by the\n
    \       # capistrano-magento2 gem for purging old content from varnish during it's
    deploy routine.\n        if (!req.http.X-Magento-Tags-Pattern &amp;&amp; !req.http.X-Pool)
    {\n            return (synth(400, \&quot;X-Magento-Tags-Pattern or X-Pool header required\&quot;));\n
    \       }\n        if (req.http.X-Magento-Tags-Pattern) {\n            ban(\&quot;obj.http.X-Magento-Tags
    ~ \&quot; + req.http.X-Magento-Tags-Pattern);\n        }\n        if (req.http.X-Pool)
    {\n            ban(\&quot;obj.http.X-Pool ~ \&quot; + req.http.X-Pool);\n        }\n        return
    (synth(200, \&quot;Purged\&quot;));\n    }\n\n    if (req.method != \&quot;GET\&quot; &amp;&amp;\n        req.method
    != \&quot;HEAD\&quot; &amp;&amp;\n        req.method != \&quot;PUT\&quot; &amp;&amp;\n        req.method != \&quot;POST\&quot;
    &amp;&amp;\n        req.method != \&quot;TRACE\&quot; &amp;&amp;\n        req.method != \&quot;OPTIONS\&quot; &amp;&amp;\n        req.method
    != \&quot;DELETE\&quot;) {\n            /* Non-RFC2616 or CONNECT which is weird. */\n            return
    (pipe);\n    }\n\n    # We only deal with GET and HEAD by default\n    if (req.method
    != \&quot;GET\&quot; &amp;&amp; req.method != \&quot;HEAD\&quot;) {\n        return (pass);\n    }\n\n    #
    Bypass shopping cart, checkout and search requests\n    if (req.url ~ \&quot;/checkout\&quot;
    || req.url ~ \&quot;/catalogsearch\&quot;) {\n        return (pass);\n    }\n\n    # Bypass
    admin\n    if (req.url ~ \&quot;^/admin($|/.*)\&quot;) {\n        return (pass);\n    }\n\n
    \   # Bypass health check requests\n    if (req.url ~ \&quot;/pub/health_check.php\&quot;)
    {\n        return (pass);\n    }\n\n    # Set initial grace period usage status\n
    \   set req.http.grace = \&quot;none\&quot;;\n\n    # normalize url in case of leading HTTP
    scheme and domain\n    set req.url = regsub(req.url, \&quot;^http[s]?://\&quot;, \&quot;\&quot;);\n\n
    \   # collect all cookies\n    std.collect(req.http.Cookie);\n\n    # Compression
    filter. See https://www.varnish-cache.org/trac/wiki/FAQ/Compression\n    if (req.http.Accept-Encoding)
    {\n        if (req.url ~ \&quot;\\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$\&quot;)
    {\n            # No point in compressing these\n            unset req.http.Accept-Encoding;\n
    \       } elsif (req.http.Accept-Encoding ~ \&quot;gzip\&quot;) {\n            set req.http.Accept-Encoding
    = \&quot;gzip\&quot;;\n        } elsif (req.http.Accept-Encoding ~ \&quot;deflate\&quot; &amp;&amp; req.http.user-agent
    !~ \&quot;MSIE\&quot;) {\n            set req.http.Accept-Encoding = \&quot;deflate\&quot;;\n        }
    else {\n            # unknown algorithm\n            unset req.http.Accept-Encoding;\n
    \       }\n    }\n\n    # Remove all marketing get parameters to minimize the cache
    objects\n    if (req.url ~ \&quot;(\\?|&amp;)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=\&quot;)
    {\n        set req.url = regsuball(req.url, \&quot;(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&amp;?\&quot;,
    \&quot;\&quot;);\n        set req.url = regsub(req.url, \&quot;[?|&amp;]+$\&quot;, \&quot;\&quot;);\n    }\n\n    #
    Static files caching\n    if (req.url ~ \&quot;^/(pub/)?(media|static)/\&quot;) {\n        return
    (pass);\n    }\n\n    return (hash);\n}\n\nsub vcl_hash {\n    if (req.http.cookie
    ~ \&quot;X-Magento-Vary=\&quot;) {\n        hash_data(regsub(req.http.cookie, \&quot;^.*?X-Magento-Vary=([^;]+);*.*$\&quot;,
    \&quot;\\1\&quot;));\n    }\n\n    # For multi site configurations to not cache each other's
    content\n    if (req.http.host) {\n        hash_data(req.http.host);\n    } else
    {\n        hash_data(server.ip);\n    }\n\n    if (req.url ~ \&quot;/graphql\&quot;) {\n        call
    process_graphql_headers;\n    }\n\n    # To make sure http users don't see ssl warning\n
    \   if (req.http.X-Forwarded-Proto) {\n        hash_data(req.http.X-Forwarded-Proto);\n
    \   }\n    \n}\n\nsub process_graphql_headers {\n    if (req.http.Store) {\n        hash_data(req.http.Store);\n
    \   }\n    if (req.http.Content-Currency) {\n        hash_data(req.http.Content-Currency);\n
    \   }\n}\n\nsub vcl_backend_response {\n\n    set beresp.grace = 3d;\n\n    if (beresp.http.content-type
    ~ \&quot;text\&quot;) {\n        set beresp.do_esi = true;\n    }\n\n    if (bereq.url ~ \&quot;\\.js$\&quot;
    || beresp.http.content-type ~ \&quot;text\&quot;) {\n        set beresp.do_gzip = true;\n
    \   }\n\n    if (beresp.http.X-Magento-Debug) {\n        set beresp.http.X-Magento-Cache-Control
    = beresp.http.Cache-Control;\n    }\n\n    # cache only successfully responses and
    404s\n    if (beresp.status != 200 &amp;&amp; beresp.status != 404) {\n        set beresp.ttl
    = 0s;\n        set beresp.uncacheable = true;\n        return (deliver);\n    }
    elsif (beresp.http.Cache-Control ~ \&quot;private\&quot;) {\n        set beresp.uncacheable
    = true;\n        set beresp.ttl = 86400s;\n        return (deliver);\n    }\n\n
    \   # validate if we need to cache it and prevent from setting cookie\n    if (beresp.ttl
    &gt; 0s &amp;&amp; (bereq.method == \&quot;GET\&quot; || bereq.method == \&quot;HEAD\&quot;)) {\n        unset
    beresp.http.set-cookie;\n    }\n\n    # If page is not cacheable then bypass varnish
    for 2 minutes as Hit-For-Pass\n    if (beresp.ttl &lt;= 0s ||\n        beresp.http.Surrogate-control
    ~ \&quot;no-store\&quot; ||\n        (!beresp.http.Surrogate-Control &amp;&amp;\n        beresp.http.Cache-Control
    ~ \&quot;no-cache|no-store\&quot;) ||\n        beresp.http.Vary == \&quot;*\&quot;) {\n        # Mark
    as Hit-For-Pass for the next 2 minutes\n        set beresp.ttl = 120s;\n        set
    beresp.uncacheable = true;\n    }\n\n    return (deliver);\n}\n\nsub vcl_deliver
    {\n    if (resp.http.X-Magento-Debug) {\n        if (resp.http.x-varnish ~ \&quot; \&quot;)
    {\n            set resp.http.X-Magento-Cache-Debug = \&quot;HIT\&quot;;\n            set resp.http.Grace
    = req.http.grace;\n        } else {\n            set resp.http.X-Magento-Cache-Debug
    = \&quot;MISS\&quot;;\n        }\n    } else {\n        unset resp.http.Age;\n    }\n\n    #
    Not letting browser to cache non-static files.\n    if (resp.http.Cache-Control
    !~ \&quot;private\&quot; &amp;&amp; req.url !~ \&quot;^/(pub/)?(media|static)/\&quot;) {\n        set resp.http.Pragma
    = \&quot;no-cache\&quot;;\n        set resp.http.Expires = \&quot;-1\&quot;;\n        set resp.http.Cache-Control
    = \&quot;no-store, no-cache, must-revalidate, max-age=0\&quot;;\n    }\n\n    unset resp.http.X-Magento-Debug;\n
    \   unset resp.http.X-Magento-Tags;\n    unset resp.http.X-Powered-By;\n    unset
    resp.http.Server;\n    unset resp.http.X-Varnish;\n    unset resp.http.Via;\n    unset
    resp.http.Link;\n}\n\nsub vcl_hit {\n    if (obj.ttl &gt;= 0s) {\n        # Hit within
    TTL period\n        return (deliver);\n    }\n    if (std.healthy(req.backend_hint))
    {\n        if (obj.ttl + 300s &gt; 0s) {\n            # Hit after TTL expiration, but
    within grace period\n            set req.http.grace = \&quot;normal (healthy server)\&quot;;\n
    \           return (deliver);\n        } else {\n            # Hit after TTL and
    grace expiration\n            return (miss);\n        }\n    } else {\n        #
    server is not healthy, retrieve from cache\n        set req.http.grace = \&quot;unlimited
    (unhealthy server)\&quot;;\n        return (deliver);\n    }\n}\n&quot;
  nginx.conf: |
    worker_processes auto;
  
    events {
        worker_connections 1024;
    }
  
    pcre_jit on;
    error_log /var/log/nginx/error.log warn;
    include /etc/nginx/modules/*.conf;
  
    http {
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        server_tokens off;
        client_max_body_size 15m;
        keepalive_timeout 30;
        sendfile on;
        tcp_nodelay on;
        gzip_vary on;
        log_format main '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
        '$status $body_bytes_sent &quot;$http_referer&quot; '
        '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';
        access_log /var/log/nginx/access.log main;
        include /etc/nginx/conf.d/*.conf;
    }
</code></pre>
<p><code>nginx.conf</code>:</p>
<pre><code>worker_processes auto;

events {
    worker_connections 1024;
}

pcre_jit on;
error_log /var/log/nginx/error.log warn;
include /etc/nginx/modules/*.conf;

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    server_tokens off;
    client_max_body_size 15m;
    keepalive_timeout 30;
    sendfile on;
    tcp_nodelay on;
    gzip_vary on;
    log_format main '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
    '$status $body_bytes_sent &quot;$http_referer&quot; '
    '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';
    access_log /var/log/nginx/access.log main;
    include /etc/nginx/conf.d/*.conf;
}
</code></pre>
<p><code>default.vcl.tmpl</code>:</p>
<pre><code>vcl 4.0;

import std;
import directors;

{{ range .Frontends }}
backend {{ .Name }} {
    .host = &quot;{{ .Host }}&quot;;
    .port = &quot;{{ .Port }}&quot;;
}
{{- end }}

{{ range .Backends }}
backend be-{{ .Name }} {
    .host = &quot;{{ .Host }}&quot;;
    .port = &quot;{{ .Port }}&quot;;
}
{{- end }}

acl purge {
    &quot;127.0.0.1&quot;;
    &quot;localhost&quot;;
    &quot;::1&quot;;
    {{- range .Frontends }}
    &quot;{{ .Host }}&quot;;
    {{- end }}
    {{- range .Backends }}
    &quot;{{ .Host }}&quot;;
    {{- end }}
}

sub vcl_init {
    new cluster = directors.hash();

    {{ range .Frontends -}}
    cluster.add_backend({{ .Name }}, 1);
    {{ end }}

    new lb = directors.round_robin();

    {{ range .Backends -}}
    lb.add_backend(be-{{ .Name }});
    {{ end }}
}

sub vcl_recv {

    unset req.http.x-cache;
    set req.backend_hint = cluster.backend(req.url);
    set req.http.x-shard = req.backend_hint;
    if (req.http.x-shard != server.identity) {
        return(pass);
    }
    set req.backend_hint = lb.backend();

    if (req.method == &quot;PURGE&quot;) {
        if (client.ip !~ purge) {
            return (synth(405, &quot;Method not allowed&quot;));
        }
        # To use the X-Pool header for purging varnish during automated deployments, make sure the X-Pool header
        # has been added to the response in your backend server config. This is used, for example, by the
        # capistrano-magento2 gem for purging old content from varnish during it's deploy routine.
        if (!req.http.X-Magento-Tags-Pattern &amp;&amp; !req.http.X-Pool) {
            return (synth(400, &quot;X-Magento-Tags-Pattern or X-Pool header required&quot;));
        }
        if (req.http.X-Magento-Tags-Pattern) {
            ban(&quot;obj.http.X-Magento-Tags ~ &quot; + req.http.X-Magento-Tags-Pattern);
        }
        if (req.http.X-Pool) {
            ban(&quot;obj.http.X-Pool ~ &quot; + req.http.X-Pool);
        }
        return (synth(200, &quot;Purged&quot;));
    }

    if (req.method != &quot;GET&quot; &amp;&amp;
        req.method != &quot;HEAD&quot; &amp;&amp;
        req.method != &quot;PUT&quot; &amp;&amp;
        req.method != &quot;POST&quot; &amp;&amp;
        req.method != &quot;TRACE&quot; &amp;&amp;
        req.method != &quot;OPTIONS&quot; &amp;&amp;
        req.method != &quot;DELETE&quot;) {
            /* Non-RFC2616 or CONNECT which is weird. */
            return (pipe);
    }

    # We only deal with GET and HEAD by default
    if (req.method != &quot;GET&quot; &amp;&amp; req.method != &quot;HEAD&quot;) {
        return (pass);
    }

    # Bypass shopping cart, checkout and search requests
    if (req.url ~ &quot;/checkout&quot; || req.url ~ &quot;/catalogsearch&quot;) {
        return (pass);
    }

    # Bypass admin
    if (req.url ~ &quot;^/admin($|/.*)&quot;) {
        return (pass);
    }

    # Bypass health check requests
    if (req.url ~ &quot;/pub/health_check.php&quot;) {
        return (pass);
    }

    # Set initial grace period usage status
    set req.http.grace = &quot;none&quot;;

    # normalize url in case of leading HTTP scheme and domain
    set req.url = regsub(req.url, &quot;^http[s]?://&quot;, &quot;&quot;);

    # collect all cookies
    std.collect(req.http.Cookie);

    # Compression filter. See https://www.varnish-cache.org/trac/wiki/FAQ/Compression
    if (req.http.Accept-Encoding) {
        if (req.url ~ &quot;\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$&quot;) {
            # No point in compressing these
            unset req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ &quot;gzip&quot;) {
            set req.http.Accept-Encoding = &quot;gzip&quot;;
        } elsif (req.http.Accept-Encoding ~ &quot;deflate&quot; &amp;&amp; req.http.user-agent !~ &quot;MSIE&quot;) {
            set req.http.Accept-Encoding = &quot;deflate&quot;;
        } else {
            # unknown algorithm
            unset req.http.Accept-Encoding;
        }
    }

    # Remove all marketing get parameters to minimize the cache objects
    if (req.url ~ &quot;(\?|&amp;)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=&quot;) {
        set req.url = regsuball(req.url, &quot;(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&amp;?&quot;, &quot;&quot;);
        set req.url = regsub(req.url, &quot;[?|&amp;]+$&quot;, &quot;&quot;);
    }

    # Static files caching
    if (req.url ~ &quot;^/(pub/)?(media|static)/&quot;) {
        return (pass);
    }

    return (hash);
}

sub vcl_hash {
    if (req.http.cookie ~ &quot;X-Magento-Vary=&quot;) {
        hash_data(regsub(req.http.cookie, &quot;^.*?X-Magento-Vary=([^;]+);*.*$&quot;, &quot;\1&quot;));
    }

    # For multi site configurations to not cache each other's content
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    if (req.url ~ &quot;/graphql&quot;) {
        call process_graphql_headers;
    }

    # To make sure http users don't see ssl warning
    if (req.http.X-Forwarded-Proto) {
        hash_data(req.http.X-Forwarded-Proto);
    }
    
}

sub process_graphql_headers {
    if (req.http.Store) {
        hash_data(req.http.Store);
    }
    if (req.http.Content-Currency) {
        hash_data(req.http.Content-Currency);
    }
}

sub vcl_backend_response {

    set beresp.grace = 3d;

    if (beresp.http.content-type ~ &quot;text&quot;) {
        set beresp.do_esi = true;
    }

    if (bereq.url ~ &quot;\.js$&quot; || beresp.http.content-type ~ &quot;text&quot;) {
        set beresp.do_gzip = true;
    }

    if (beresp.http.X-Magento-Debug) {
        set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
    }

    # cache only successfully responses and 404s
    if (beresp.status != 200 &amp;&amp; beresp.status != 404) {
        set beresp.ttl = 0s;
        set beresp.uncacheable = true;
        return (deliver);
    } elsif (beresp.http.Cache-Control ~ &quot;private&quot;) {
        set beresp.uncacheable = true;
        set beresp.ttl = 86400s;
        return (deliver);
    }

    # validate if we need to cache it and prevent from setting cookie
    if (beresp.ttl &gt; 0s &amp;&amp; (bereq.method == &quot;GET&quot; || bereq.method == &quot;HEAD&quot;)) {
        unset beresp.http.set-cookie;
    }

    # If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass
    if (beresp.ttl &lt;= 0s ||
        beresp.http.Surrogate-control ~ &quot;no-store&quot; ||
        (!beresp.http.Surrogate-Control &amp;&amp;
        beresp.http.Cache-Control ~ &quot;no-cache|no-store&quot;) ||
        beresp.http.Vary == &quot;*&quot;) {
        # Mark as Hit-For-Pass for the next 2 minutes
        set beresp.ttl = 120s;
        set beresp.uncacheable = true;
    }

    return (deliver);
}

sub vcl_deliver {
    if (resp.http.X-Magento-Debug) {
        if (resp.http.x-varnish ~ &quot; &quot;) {
            set resp.http.X-Magento-Cache-Debug = &quot;HIT&quot;;
            set resp.http.Grace = req.http.grace;
        } else {
            set resp.http.X-Magento-Cache-Debug = &quot;MISS&quot;;
        }
    } else {
        unset resp.http.Age;
    }

    # Not letting browser to cache non-static files.
    if (resp.http.Cache-Control !~ &quot;private&quot; &amp;&amp; req.url !~ &quot;^/(pub/)?(media|static)/&quot;) {
        set resp.http.Pragma = &quot;no-cache&quot;;
        set resp.http.Expires = &quot;-1&quot;;
        set resp.http.Cache-Control = &quot;no-store, no-cache, must-revalidate, max-age=0&quot;;
    }

    unset resp.http.X-Magento-Debug;
    unset resp.http.X-Magento-Tags;
    unset resp.http.X-Powered-By;
    unset resp.http.Server;
    unset resp.http.X-Varnish;
    unset resp.http.Via;
    unset resp.http.Link;
}

sub vcl_hit {
    if (obj.ttl &gt;= 0s) {
        # Hit within TTL period
        return (deliver);
    }
    if (std.healthy(req.backend_hint)) {
        if (obj.ttl + 300s &gt; 0s) {
            # Hit after TTL expiration, but within grace period
            set req.http.grace = &quot;normal (healthy server)&quot;;
            return (deliver);
        } else {
            # Hit after TTL and grace expiration
            return (miss);
        }
    } else {
        # server is not healthy, retrieve from cache
        set req.http.grace = &quot;unlimited (unhealthy server)&quot;;
        return (deliver);
    }
}
</code></pre>
<p>How come that the second file is not imported correctly? Latest Helm version and latest Go version.</p>
<p>Anyone has any ideas? The encoding of both files on VSCode shows as <code>UTF8</code>.</p>

Rafael Moreira
<p>They're actually equivalent from YAML's PoV, just not as pretty, but most important for your specific case it's because yaml cannot represent <strong>trailing</strong> whitespace without quoting it, which is what it did due to line 164 of your .tmpl file, as seen by the <code>\n    \n</code> in:</p>
<pre class="lang-yaml prettyprint-override"><code>    \   }\n    \n}\n\nsub process_graphql_headers {\n    if (req.http.Store) {\n        hash_data(req.http.Store);\n
</code></pre>
<pre><code>$ sed -ne 164p default.vcl.tmpl | xxd
00000000: 2020 2020 0a                                 .
</code></pre>
<p>turning on &quot;strip trailing whitespace&quot; in your editor will help that, or for this specific case you can just fix line 164</p>
