apiVersion: v1
kind: ConfigMap
metadata:
  name: varnish-config
data:
  default.vcl: |
    vcl 4.1;

    import std;
    import querystring;
    import dynamic;
    import directors;

    # Default backend definition
    backend default {
     .host = "127.0.0.1";
     .port = "80";
    }

    # Upstream backend probe
    probe backend_probe {
      .request =
      "GET /health HTTP/1.1"
      "Host: localhost"
      "User-Agent: Varnish Health Probe"
      "Connection: close";

      .interval = 10s;
      .timeout = 10s;
      .window = 5;
      .threshold = 3;
    }

    # Varnish shard probe
    probe varnish_probe {
      .request =
      "GET /varnish_health HTTP/1.1"
      "Host: localhost"
      "User-Agent: Varnish Health Probe"
      "Connection: close";

      .interval = 10s;
      .timeout = 10s;
      .window = 5;
      .threshold = 3;
    }

    # Varnish shard backends, should match your replica count
    backend varnish-0 {
      .host = "varnish-0.varnish.default.svc";
      .port = "80";
      .probe = varnish_probe;
    }

    backend varnish-1 {
      .host = "varnish-1.varnish.default.svc";
      .port = "80";
      .probe = varnish_probe;
    }

    sub vcl_init {
      # Set up the shard director
      new shard_director = directors.shard();
      shard_director.add_backend(varnish-0);
      shard_director.add_backend(varnish-1);
      shard_director.reconfigure();

      # Set up the upstream backend
      new upstream = dynamic.director(
        port = "8081",
        probe = backend_probe,
        ttl = 10s, # How often to refresh the DNS
        first_byte_timeout = 60s, # How long to wait before we receive a first byte from our backend
        connect_timeout = 5s, # How long to wait for a backend connection
        between_bytes_timeout = 2s); # How long to wait between bytes received from our backend

      # Initialize the queryfilter
      new queryfilter = querystring.filter(sort = true, uniq = true);
      # Add whitelisted query parameters
      # Effects
      queryfilter.add_string("blur");
      queryfilter.add_string("grayscale");
    }

    sub vcl_recv {
      # Healthcheck for k8s
      if (req.url ~ "^/varnish_health") {
        return (synth(200, "healthcheck"));
      }

      # Sort the query parameters, only keep ones in our whitelist
      set req.url = queryfilter.apply(mode = keep);

      # Get the backend from the shard director
      set req.backend_hint = shard_director.backend(resolve=NOW);
      set req.http.X-Shard = req.backend_hint;

      # Pass the request to the other varnish node
      if (req.http.X-Shard != server.identity) {
        return(pass);
      }

      # Pass the request to the backend
      set req.backend_hint = upstream.backend("image-service.default.svc");

      # Unset unwanted headers
      unset req.http.Cookie;

      if (std.healthy(req.backend_hint)) {
        # Change the behavior for healthy backends: Cap grace to 10s
        set req.grace = 10s;
      }
    }

    sub vcl_hash {
      # Only hash based on the url
      hash_data(req.url);

      # Don't go to default vcl_hash
      return (lookup);
    }

    sub vcl_backend_response {
      # Allow stale content, in case the backend goes down.
      # Make Varnish keep all objects for 6 hours beyond their TTL
      set beresp.keep = 6h;

      if (beresp.status >= 500 && bereq.is_bgfetch) {
        return (abandon);
      }

      # Gzip responses
      if (beresp.http.content-type ~ "(text|application)") {
        set beresp.do_gzip = true;
      }
    }

    sub vcl_synth {
      # Healthcheck for k8s
      if (resp.reason == "healthcheck") {
          set resp.http.Content-Type = "text/plain; charset=utf-8";
          synthetic("OK");
          return (deliver);
      }
    }
