Skip to content

Commit

Permalink
Add exported services func for listing exported services in a given p…
Browse files Browse the repository at this point in the history
…artition
  • Loading branch information
jm96441n authored and nathancoleman committed May 21, 2024
1 parent 1bd9b0d commit 4a33247
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 62 deletions.
143 changes: 143 additions & 0 deletions dependency/consul_exported_services.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package dependency

import (
"log"
"net/url"
"slices"
"time"

capi "github.com/hashicorp/consul/api"
"github.com/pkg/errors"
)

const (
exportedServicesEndpointLabel = "list.exportedServices"

// ListExportedServicesQuerySleepTime is the amount of time to sleep between
// queries, since the endpoint does not support blocking queries.
ListExportedServicesQuerySleepTime = 15 * time.Second
)

// Ensure implements
var _ Dependency = (*ListExportedServicesQuery)(nil)

// ListExportedServicesQuery is the representation of a requested exported services
// dependency from inside a template.
type ListExportedServicesQuery struct {
stopCh chan struct{}
partition string
}

type ExportedService struct {
// Name of the service
Service string

// Partition of the service
Partition string

// Namespace of the service
Namespace string

// Consumers is a list of downstream consumers of the service.
Consumers ResolvedConsumers
}

type ResolvedConsumers struct {
Peers []string
Partitions []string
}

func fromConsulExportedService(svc capi.ResolvedExportedService) ExportedService {
return ExportedService{
Service: svc.Service,
Consumers: ResolvedConsumers{
Peers: slices.Clone(svc.Consumers.Peers),
Partitions: slices.Clone(svc.Consumers.Partitions),
},
}
}

// NewListExportedServicesQuery parses a string of the format @dc.
func NewListExportedServicesQuery(s string) (*ListExportedServicesQuery, error) {
return &ListExportedServicesQuery{
stopCh: make(chan struct{}, 1),
partition: s,
}, nil
}

func (c *ListExportedServicesQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
opts = opts.Merge(&QueryOptions{
ConsulPartition: c.partition,
})

log.Printf("[TRACE] %s: GET %s", c, &url.URL{
Path: "/v1/exported-services",
RawQuery: opts.String(),
})

// This is certainly not elegant, but the partitions endpoint does not support
// blocking queries, so we are going to "fake it until we make it". When we
// first query, the LastIndex will be "0", meaning we should immediately
// return data, but future calls will include a LastIndex. If we have a
// LastIndex in the query metadata, sleep for 15 seconds before asking Consul
// again.
//
// This is probably okay given the frequency in which partitions actually
// change, but is technically not edge-triggering.
if opts.WaitIndex != 0 {
log.Printf("[TRACE] %s: long polling for %s", c, ListExportedServicesQuerySleepTime)

select {
case <-c.stopCh:
return nil, nil, ErrStopped
case <-time.After(ListExportedServicesQuerySleepTime):
}
}

// TODO Consider using a proper context
consulExportedServices, qm, err := clients.Consul().ExportedServices(opts.ToConsulOpts())
if err != nil {
return nil, nil, errors.Wrapf(err, c.String())
}

exportedServices := make([]ExportedService, 0, len(consulExportedServices))
for _, svc := range consulExportedServices {
exportedServices = append(exportedServices, fromConsulExportedService(svc))
}

log.Printf("[TRACE] %s: returned %d results", c, len(exportedServices))

slices.SortStableFunc(exportedServices, func(i, j ExportedService) int {
if i.Service < j.Service {
return -1
} else if i.Service > j.Service {
return 1
}
return 0
})

rm := &ResponseMetadata{
LastContact: qm.LastContact,
LastIndex: qm.LastIndex,
}

return exportedServices, rm, nil
}

// CanShare returns if this dependency is shareable.
// TODO What is this?
func (c *ListExportedServicesQuery) CanShare() bool {
return true
}

func (c *ListExportedServicesQuery) String() string {
return exportedServicesEndpointLabel
}

func (c *ListExportedServicesQuery) Stop() {
close(c.stopCh)
}

func (c *ListExportedServicesQuery) Type() Type {
return TypeConsul
}
17 changes: 9 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
module github.com/hashicorp/consul-template

go 1.21
go 1.22

require (
github.com/BurntSushi/toml v1.3.2
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/hashicorp/consul/api v1.26.1
github.com/hashicorp/consul/api v1.28.3
github.com/hashicorp/consul/sdk v0.15.0
github.com/hashicorp/go-gatedio v0.5.0
github.com/hashicorp/go-hclog v1.5.0
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-rootcerts v1.0.2
github.com/hashicorp/go-sockaddr v1.0.6
Expand All @@ -25,14 +25,14 @@ require (
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/sys v0.19.0
golang.org/x/sys v0.20.0
gopkg.in/yaml.v2 v2.4.0
)

require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/hashicorp/vault/api/auth/kubernetes v0.5.0
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/text v0.14.0
)

Expand All @@ -41,10 +41,11 @@ require (
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/consul/proto-public v0.6.1 // indirect
github.com/hashicorp/cronexpr v1.1.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
Expand All @@ -54,10 +55,10 @@ require (
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
Expand Down
Loading

0 comments on commit 4a33247

Please sign in to comment.