{"action":"created","issue":{"url":"https://api.github.com/repos/hashicorp/consul-template/issues/209","labels_url":"https://api.github.com/repos/hashicorp/consul-template/issues/209/labels{/name}","comments_url":"https://api.github.com/repos/hashicorp/consul-template/issues/209/comments","events_url":"https://api.github.com/repos/hashicorp/consul-template/issues/209/events","html_url":"https://github.com/hashicorp/consul-template/pull/209","id":58974536,"number":209,"title":"Add byKey function for grouping the results of tree by its top key","user":{"login":"sethvargo","id":408570,"avatar_url":"https://avatars.githubusercontent.com/u/408570?v=3","gravatar_id":"","url":"https://api.github.com/users/sethvargo","html_url":"https://github.com/sethvargo","followers_url":"https://api.github.com/users/sethvargo/followers","following_url":"https://api.github.com/users/sethvargo/following{/other_user}","gists_url":"https://api.github.com/users/sethvargo/gists{/gist_id}","starred_url":"https://api.github.com/users/sethvargo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sethvargo/subscriptions","organizations_url":"https://api.github.com/users/sethvargo/orgs","repos_url":"https://api.github.com/users/sethvargo/repos","events_url":"https://api.github.com/users/sethvargo/events{/privacy}","received_events_url":"https://api.github.com/users/sethvargo/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-02-25T21:41:05Z","updated_at":"2015-03-02T18:17:06Z","closed_at":"2015-02-27T19:14:31Z","pull_request":{"url":"https://api.github.com/repos/hashicorp/consul-template/pulls/209","html_url":"https://github.com/hashicorp/consul-template/pull/209","diff_url":"https://github.com/hashicorp/consul-template/pull/209.diff","patch_url":"https://github.com/hashicorp/consul-template/pull/209.patch"},"body":"This adds a new `byKey` function for the template that accepts a list of KV pairs (most likely from `tree`) and \"groups\" them by the top-most key. You can see the comment in template_functions.go for a more concrete example of what that might look like.\r\n\r\n- Fixes https://github.com/hashicorp/consul-template/issues/207\r\n\r\n/cc @ryanuber @armon "},"comment":{"url":"https://api.github.com/repos/hashicorp/consul-template/issues/comments/76767844","html_url":"https://github.com/hashicorp/consul-template/pull/209#issuecomment-76767844","issue_url":"https://api.github.com/repos/hashicorp/consul-template/issues/209","id":76767844,"user":{"login":"hoffoo","id":1896175,"avatar_url":"https://avatars.githubusercontent.com/u/1896175?v=3","gravatar_id":"","url":"https://api.github.com/users/hoffoo","html_url":"https://github.com/hoffoo","followers_url":"https://api.github.com/users/hoffoo/followers","following_url":"https://api.github.com/users/hoffoo/following{/other_user}","gists_url":"https://api.github.com/users/hoffoo/gists{/gist_id}","starred_url":"https://api.github.com/users/hoffoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hoffoo/subscriptions","organizations_url":"https://api.github.com/users/hoffoo/orgs","repos_url":"https://api.github.com/users/hoffoo/repos","events_url":"https://api.github.com/users/hoffoo/events{/privacy}","received_events_url":"https://api.github.com/users/hoffoo/received_events","type":"User","site_admin":false},"created_at":"2015-03-02T18:17:06Z","updated_at":"2015-03-02T18:17:06Z","body":"@sethvargo I checked both with -race, okay here is the output without GOMAXPROCS and same template as above:\r\n\r\n```\r\nINFO\r\nConsul\r\nConsul v0.5.0-41-g42a7251\r\nConsul Protocol: 2 (Understands back to: 1)\r\nConsul Template\r\nconsul-template v0.7.1.dev\r\nSTARTING CONSUL\r\n==> WARNING: Bootstrap mode enabled! Do not enable unless necessary\r\n==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1\r\n==> Starting Consul agent...\r\n==> Starting Consul agent RPC...\r\n==> Consul agent running!\r\n         Node name: 'fatpad'\r\n        Datacenter: 'dc1'\r\n            Server: true (bootstrap: true)\r\n       Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400)\r\n      Cluster Addr: 192.168.2.209 (LAN: 8301, WAN: 8302)\r\n    Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false\r\n             Atlas: <disabled>\r\n\r\n==> Log data will now stream in as it occurs:\r\n\r\n    2015/03/02 10:11:54 [INFO] serf: EventMemberJoin: fatpad 192.168.2.209\r\n    2015/03/02 10:11:54 [INFO] serf: EventMemberJoin: fatpad.dc1 192.168.2.209\r\n    2015/03/02 10:11:54 [INFO] raft: Node at 192.168.2.209:8300 [Follower] entering Follower state\r\n    2015/03/02 10:11:54 [WARN] serf: Failed to re-join any previously known node\r\n    2015/03/02 10:11:54 [WARN] serf: Failed to re-join any previously known node\r\n    2015/03/02 10:11:54 [INFO] consul: adding server fatpad (Addr: 192.168.2.209:8300) (DC: dc1)\r\n    2015/03/02 10:11:54 [INFO] consul: adding server fatpad.dc1 (Addr: 192.168.2.209:8300) (DC: dc1)\r\n    2015/03/02 10:11:55 [ERR] agent: failed to sync remote state: No cluster leader\r\n    2015/03/02 10:11:56 [WARN] raft: Heartbeat timeout reached, starting election\r\n    2015/03/02 10:11:56 [INFO] raft: Node at 192.168.2.209:8300 [Candidate] entering Candidate state\r\n    2015/03/02 10:11:56 [INFO] raft: Election won. Tally: 1\r\n    2015/03/02 10:11:56 [INFO] raft: Node at 192.168.2.209:8300 [Leader] entering Leader state\r\n    2015/03/02 10:11:56 [INFO] raft: Disabling EnableSingleNode (bootstrap)\r\n    2015/03/02 10:11:56 [INFO] consul: cluster leadership acquired\r\n    2015/03/02 10:11:56 [INFO] consul: New leader elected: fatpad\r\n\r\nCREATING KEYS\r\ntruetruetruetruetrue\r\nSTARTING CONSUL-TEMPLATE\r\n2015/03/02 10:12:02 [INFO] (runner) creating new runner (dry: false, once: false)\r\n2015/03/02 10:12:02 [INFO] (runner) creating consul/api client\r\n2015/03/02 10:12:02 [DEBUG] (runner) setting basic auth\r\n2015/03/02 10:12:02 [INFO] (runner) creating Watcher\r\n2015/03/02 10:12:02 [INFO] (runner) starting\r\n2015/03/02 10:12:02 [DEBUG] (runner) running initial templates\r\n2015/03/02 10:12:02 [INFO] (runner) running\r\n2015/03/02 10:12:02 [DEBUG] (runner) checking template ./template.ctmpl\r\n2015/03/02 10:12:02 [DEBUG] (brain) does not have data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [DEBUG] (brain) does not have data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [INFO] (runner) was not watching 2 dependencies\r\n2015/03/02 10:12:02 [INFO] (watcher) adding \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [DEBUG] (watcher) \"storeKeyPrefix(groups/)\" starting\r\n2015/03/02 10:12:02 [INFO] (watcher) adding \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [DEBUG] (watcher) \"storeKeyPrefix(services/)\" starting\r\n2015/03/02 10:12:02 [INFO] (runner) diffing and updating dependencies\r\n2015/03/02 10:12:02 [INFO] (runner) watching 2 dependencies\r\n2015/03/02 10:12:02 [DEBUG] (view) \"storeKeyPrefix(groups/)\" starting fetch\r\n2015/03/02 10:12:02 [DEBUG] (\"storeKeyPrefix(groups/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:0 WaitTime:1m0s Token:}\r\n2015/03/02 10:12:02 [DEBUG] (view) \"storeKeyPrefix(services/)\" starting fetch\r\n2015/03/02 10:12:02 [DEBUG] (\"storeKeyPrefix(services/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:0 WaitTime:1m0s Token:}\r\n2015/03/02 10:12:02 [DEBUG] (\"storeKeyPrefix(services/)\") Consul returned 2 key pairs\r\n2015/03/02 10:12:02 [INFO] (view) \"storeKeyPrefix(services/)\" received data from consul\r\n2015/03/02 10:12:02 [DEBUG] (runner) receiving dependency \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [INFO] (brain) remembering \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [INFO] (runner) running\r\n2015/03/02 10:12:02 [DEBUG] (runner) checking template ./template.ctmpl\r\n2015/03/02 10:12:02 [DEBUG] (view) \"storeKeyPrefix(services/)\" starting fetch\r\n2015/03/02 10:12:02 [DEBUG] (\"storeKeyPrefix(services/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:16 WaitTime:1m0s Token:}\r\n2015/03/02 10:12:02 [DEBUG] (brain) does not have data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [INFO] (brain) recalling data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [DEBUG] (brain) does not have data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [DEBUG] (runner) \"./template.ctmpl\" missing data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [DEBUG] (runner) cannot render (some dependencies do not have data yet)\r\n2015/03/02 10:12:02 [INFO] (runner) diffing and updating dependencies\r\n2015/03/02 10:12:02 [DEBUG] (runner) \"storeKeyPrefix(groups/)\" is still needed\r\n2015/03/02 10:12:02 [DEBUG] (runner) \"storeKeyPrefix(services/)\" is still needed\r\n2015/03/02 10:12:02 [INFO] (runner) watching 2 dependencies\r\n2015/03/02 10:12:02 [DEBUG] (\"storeKeyPrefix(groups/)\") Consul returned 3 key pairs\r\n2015/03/02 10:12:02 [INFO] (view) \"storeKeyPrefix(groups/)\" received data from consul\r\n2015/03/02 10:12:02 [DEBUG] (runner) receiving dependency \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [INFO] (brain) remembering \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [INFO] (runner) running\r\n2015/03/02 10:12:02 [DEBUG] (runner) checking template ./template.ctmpl\r\n2015/03/02 10:12:02 [DEBUG] (view) \"storeKeyPrefix(groups/)\" starting fetch\r\n2015/03/02 10:12:02 [DEBUG] (\"storeKeyPrefix(groups/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:14 WaitTime:1m0s Token:}\r\n2015/03/02 10:12:02 [INFO] (brain) recalling data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [INFO] (brain) recalling data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [INFO] (brain) recalling data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:12:02 [INFO] (brain) recalling data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:12:02 [DEBUG] (runner) checking ctemplate &{Source:./template.ctmpl Destination:./out Command:}\r\n2015/03/02 10:12:02 [DEBUG] (runner) wouldRender: true, didRender: true\r\n2015/03/02 10:12:02 [INFO] (runner) diffing and updating dependencies\r\n2015/03/02 10:12:02 [DEBUG] (runner) \"storeKeyPrefix(groups/)\" is still needed\r\n2015/03/02 10:12:02 [DEBUG] (runner) \"storeKeyPrefix(services/)\" is still needed\r\n2015/03/02 10:12:02 [INFO] (runner) watching 2 dependencies\r\n\r\nRESULT\r\n### groups\r\n\r\n\r\ndefine hostgroup {\r\n    hostgroup_name elasticsearch\r\n    members es1,es2,es3,\r\n}\r\n\r\n\r\n### services\r\n\r\n\r\n[1]-  Killed                  consul agent -server -bootstrap -data-dir $DATADIR\r\n[2]+  Killed                  consul-template -template ./template.ctmpl:./out -log-level debug\r\n```\r\n\r\nAnd here is with GOMAXPROCS=8\r\n\r\n```\r\nINFO\r\nConsul\r\nConsul v0.5.0-41-g42a7251\r\nConsul Protocol: 2 (Understands back to: 1)\r\nConsul Template\r\nconsul-template v0.7.1.dev\r\nSTARTING CONSUL\r\n==> WARNING: Bootstrap mode enabled! Do not enable unless necessary\r\n==> Starting Consul agent...\r\n==> Starting Consul agent RPC...\r\n==> Consul agent running!\r\n         Node name: 'fatpad'\r\n        Datacenter: 'dc1'\r\n            Server: true (bootstrap: true)\r\n       Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400)\r\n      Cluster Addr: 192.168.2.209 (LAN: 8301, WAN: 8302)\r\n    Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false\r\n             Atlas: <disabled>\r\n\r\n==> Log data will now stream in as it occurs:\r\n\r\n    2015/03/02 10:14:08 [INFO] raft: Node at 192.168.2.209:8300 [Follower] entering Follower state\r\n    2015/03/02 10:14:08 [INFO] serf: EventMemberJoin: fatpad 192.168.2.209\r\n    2015/03/02 10:14:08 [INFO] consul: adding server fatpad (Addr: 192.168.2.209:8300) (DC: dc1)\r\n    2015/03/02 10:14:08 [INFO] serf: EventMemberJoin: fatpad.dc1 192.168.2.209\r\n    2015/03/02 10:14:08 [INFO] consul: adding server fatpad.dc1 (Addr: 192.168.2.209:8300) (DC: dc1)\r\n    2015/03/02 10:14:09 [ERR] agent: failed to sync remote state: No cluster leader\r\n    2015/03/02 10:14:10 [WARN] raft: Heartbeat timeout reached, starting election\r\n    2015/03/02 10:14:10 [INFO] raft: Node at 192.168.2.209:8300 [Candidate] entering Candidate state\r\n    2015/03/02 10:14:10 [INFO] raft: Election won. Tally: 1\r\n    2015/03/02 10:14:10 [INFO] raft: Node at 192.168.2.209:8300 [Leader] entering Leader state\r\n    2015/03/02 10:14:10 [INFO] consul: cluster leadership acquired\r\n    2015/03/02 10:14:10 [INFO] raft: Disabling EnableSingleNode (bootstrap)\r\n    2015/03/02 10:14:10 [INFO] consul: New leader elected: fatpad\r\n    2015/03/02 10:14:10 [INFO] consul: member 'fatpad' joined, marking health alive\r\n    2015/03/02 10:14:12 [INFO] agent: Synced service 'consul'\r\n\r\nCREATING KEYS\r\ntruetruetruetruetrue\r\nSTARTING CONSUL-TEMPLATE\r\n2015/03/02 10:14:16 [INFO] (runner) creating new runner (dry: false, once: false)\r\n2015/03/02 10:14:16 [INFO] (runner) creating consul/api client\r\n2015/03/02 10:14:16 [DEBUG] (runner) setting basic auth\r\n2015/03/02 10:14:16 [INFO] (runner) creating Watcher\r\n2015/03/02 10:14:16 [INFO] (runner) starting\r\n2015/03/02 10:14:16 [DEBUG] (runner) running initial templates\r\n2015/03/02 10:14:16 [INFO] (runner) running\r\n2015/03/02 10:14:16 [DEBUG] (runner) checking template ./template.ctmpl\r\n2015/03/02 10:14:16 [DEBUG] (brain) does not have data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:14:16 [DEBUG] (brain) does not have data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:14:16 [INFO] (runner) was not watching 2 dependencies\r\n2015/03/02 10:14:16 [INFO] (watcher) adding \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:14:16 [DEBUG] (watcher) \"storeKeyPrefix(groups/)\" starting\r\n2015/03/02 10:14:16 [INFO] (watcher) adding \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:14:16 [DEBUG] (watcher) \"storeKeyPrefix(services/)\" starting\r\n2015/03/02 10:14:16 [INFO] (runner) diffing and updating dependencies\r\n2015/03/02 10:14:16 [DEBUG] (view) \"storeKeyPrefix(groups/)\" starting fetch\r\n2015/03/02 10:14:16 [INFO] (runner) watching 2 dependencies\r\n2015/03/02 10:14:16 [DEBUG] (view) \"storeKeyPrefix(services/)\" starting fetch\r\n2015/03/02 10:14:16 [DEBUG] (\"storeKeyPrefix(groups/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:0 WaitTime:1m0s Token:}\r\n2015/03/02 10:14:16 [DEBUG] (\"storeKeyPrefix(services/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:0 WaitTime:1m0s Token:}\r\n2015/03/02 10:14:16 [DEBUG] (\"storeKeyPrefix(services/)\") Consul returned 2 key pairs\r\n2015/03/02 10:14:16 [DEBUG] (\"storeKeyPrefix(groups/)\") Consul returned 3 key pairs\r\n2015/03/02 10:14:16 [INFO] (view) \"storeKeyPrefix(services/)\" received data from consul\r\n2015/03/02 10:14:16 [INFO] (view) \"storeKeyPrefix(groups/)\" received data from consul\r\n2015/03/02 10:14:16 [DEBUG] (runner) receiving dependency \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:14:16 [DEBUG] (view) \"storeKeyPrefix(services/)\" starting fetch\r\n2015/03/02 10:14:16 [DEBUG] (view) \"storeKeyPrefix(groups/)\" starting fetch\r\n2015/03/02 10:14:16 [INFO] (brain) remembering \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:14:16 [DEBUG] (\"storeKeyPrefix(services/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:9 WaitTime:1m0s Token:}\r\n2015/03/02 10:14:16 [DEBUG] (runner) receiving dependency \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:14:16 [INFO] (brain) remembering \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:14:16 [INFO] (runner) running\r\n2015/03/02 10:14:16 [DEBUG] (runner) checking template ./template.ctmpl\r\n2015/03/02 10:14:16 [DEBUG] (\"storeKeyPrefix(groups/)\") querying Consul with &{Datacenter: AllowStale:false RequireConsistent:false WaitIndex:7 WaitTime:1m0s Token:}\r\n2015/03/02 10:14:16 [INFO] (brain) recalling data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:14:16 [INFO] (brain) recalling data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:14:16 [INFO] (brain) recalling data for \"storeKeyPrefix(groups/)\"\r\n2015/03/02 10:14:16 [INFO] (brain) recalling data for \"storeKeyPrefix(services/)\"\r\n2015/03/02 10:14:16 [DEBUG] (runner) checking ctemplate &{Source:./template.ctmpl Destination:./out Command:}\r\n2015/03/02 10:14:16 [DEBUG] (runner) wouldRender: true, didRender: true\r\n2015/03/02 10:14:16 [INFO] (runner) diffing and updating dependencies\r\n2015/03/02 10:14:16 [DEBUG] (runner) \"storeKeyPrefix(groups/)\" is still needed\r\n2015/03/02 10:14:16 [DEBUG] (runner) \"storeKeyPrefix(services/)\" is still needed\r\n2015/03/02 10:14:16 [INFO] (runner) watching 2 dependencies\r\n\r\nRESULT\r\n### groups\r\n\r\n\r\ndefine hostgroup {\r\n    hostgroup_name elasticsearch\r\n    members es1,es2,es3,\r\n}\r\n\r\n\r\n### services\r\n\r\n\r\n\r\ndefine service {\r\n    use generic-service\r\n    check_command \r\n    service_description Check_elasticsearch\r\n    servicegroups elasticsearch\r\n}\r\n\r\ndefine service {\r\n    use generic-service\r\n    check_command \r\n    service_description Check_indexes\r\n    servicegroups elasticsearch\r\n}\r\n\r\n[1]-  Killed                  consul agent -server -bootstrap -data-dir $DATADIR\r\n[2]+  Killed                  consul-template -template ./template.ctmpl:./out -log-level debug\r\n```"}}