consul-template: ByMeta does not accept `services` as input

TL;DR - services output cannot be passed to ByMeta, even though the documentation says this is valid.

Consul Template version

consul-template v0.24.1 (58aa6c60)

Configuration

{{- range $subdomain, $services := (services | byMeta "ProxySubdomain") }}

Expected behavior

Per the documentation:

Takes a list of services returned by the service or services and returns a map that groups services by ServiceMeta values.

Actual behavior

2020/02/25 22:04:55.961357 [ERR] (cli) /pomerium/pomerium.yaml.tpl: execute: template: :3:53: executing "" at <"ProxySubdomain">: wrong type for value; expected []*dependency.HealthService; got []*dependency.CatalogSnippet

Steps to reproduce

  1. Try and pass the output of services to ByMeta.

References

It appears (to my amateur eye) that ByMeta explicitly expects to be passed a []*dep.HealthService: https://github.com/hashicorp/consul-template/blob/7103eb34608d642d0c7dd3f6d8c2053e166927e6/template/funcs.go#L384

By comparison, ByTag accepts an interface{}: https://github.com/hashicorp/consul-template/blob/7103eb34608d642d0c7dd3f6d8c2053e166927e6/template/funcs.go#L658

This matches the functions in question - service returns a []*dep.HealthService and services returns a []*dep.CatalogSnippet:

https://github.com/hashicorp/consul-template/blob/7103eb34608d642d0c7dd3f6d8c2053e166927e6/template/funcs.go#L429

https://github.com/hashicorp/consul-template/blob/7103eb34608d642d0c7dd3f6d8c2053e166927e6/template/funcs.go#L455

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 15 (7 by maintainers)

Most upvoted comments

Per my comment #1120 (comment) so then what would be a working example for fetching service metadata? Is there ever a .ServiceMeta or .Meta map available, and if so on what object? Or would those only become available if a service is piped through byMeta?

Buckle up, here we go:

  1. range over the list of service names returned from services.
  2. For each element, call service on the service name to get a list of service instances.
  3. From here you can:
    1. range over the list of service instances, or
    2. Just use element 0 if your service instances are identical.
  4. Use the ServiceMeta field of the service instance.

Example:

{{ range services }}
    {{ service .Name }}
        {{ with index . 0 }}
            {{ index .ServiceMeta "apibasepath" }}
        {{ end }}
    {{ end }}
{{ end }}

(Note that you can’t just do {{ with index (service .Name) 0 }} because of this caveat.)

Internally, services returns a list of CatalogSnippet objects, which only contain a Name and a Tags field - service returns a HealthService object, with all the fields you’d expect.