2015-01-06 18:40:00 +00:00
|
|
|
package api
|
|
|
|
|
2019-06-17 14:51:50 +00:00
|
|
|
import (
|
|
|
|
"net"
|
2022-01-24 15:23:08 +00:00
|
|
|
"net/url"
|
2019-06-17 14:51:50 +00:00
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
2018-09-07 14:30:47 +00:00
|
|
|
type Weights struct {
|
|
|
|
Passing int
|
|
|
|
Warning int
|
|
|
|
}
|
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
type Node struct {
|
2017-01-18 22:26:42 +00:00
|
|
|
ID string
|
2016-08-16 17:30:30 +00:00
|
|
|
Node string
|
|
|
|
Address string
|
2017-04-18 12:02:24 +00:00
|
|
|
Datacenter string
|
2016-08-16 17:30:30 +00:00
|
|
|
TaggedAddresses map[string]string
|
2017-01-11 23:44:13 +00:00
|
|
|
Meta map[string]string
|
2017-04-13 15:36:19 +00:00
|
|
|
CreateIndex uint64
|
|
|
|
ModifyIndex uint64
|
2021-07-22 19:33:22 +00:00
|
|
|
Partition string `json:",omitempty"`
|
2015-01-06 18:40:00 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 14:51:50 +00:00
|
|
|
type ServiceAddress struct {
|
|
|
|
Address string
|
|
|
|
Port int
|
|
|
|
}
|
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
type CatalogService struct {
|
2017-01-18 22:26:42 +00:00
|
|
|
ID string
|
2016-02-16 19:45:29 +00:00
|
|
|
Node string
|
|
|
|
Address string
|
2017-04-18 12:02:24 +00:00
|
|
|
Datacenter string
|
2016-08-16 17:30:30 +00:00
|
|
|
TaggedAddresses map[string]string
|
2017-01-11 23:44:13 +00:00
|
|
|
NodeMeta map[string]string
|
2016-02-16 19:45:29 +00:00
|
|
|
ServiceID string
|
|
|
|
ServiceName string
|
|
|
|
ServiceAddress string
|
2019-06-17 14:51:50 +00:00
|
|
|
ServiceTaggedAddresses map[string]ServiceAddress
|
2016-02-16 19:45:29 +00:00
|
|
|
ServiceTags []string
|
2018-02-07 00:54:42 +00:00
|
|
|
ServiceMeta map[string]string
|
2016-02-16 19:45:29 +00:00
|
|
|
ServicePort int
|
2018-09-07 14:30:47 +00:00
|
|
|
ServiceWeights Weights
|
2016-02-16 19:45:29 +00:00
|
|
|
ServiceEnableTagOverride bool
|
2019-08-09 19:19:30 +00:00
|
|
|
ServiceProxy *AgentServiceConnectProxyConfig
|
|
|
|
CreateIndex uint64
|
|
|
|
Checks HealthChecks
|
|
|
|
ModifyIndex uint64
|
2019-12-10 02:26:41 +00:00
|
|
|
Namespace string `json:",omitempty"`
|
2021-07-14 19:07:38 +00:00
|
|
|
Partition string `json:",omitempty"`
|
2015-01-06 18:40:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type CatalogNode struct {
|
|
|
|
Node *Node
|
|
|
|
Services map[string]*AgentService
|
|
|
|
}
|
|
|
|
|
2020-01-24 14:27:25 +00:00
|
|
|
type CatalogNodeServiceList struct {
|
|
|
|
Node *Node
|
|
|
|
Services []*AgentService
|
|
|
|
}
|
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
type CatalogRegistration struct {
|
2017-01-18 22:26:42 +00:00
|
|
|
ID string
|
2016-08-16 17:30:30 +00:00
|
|
|
Node string
|
|
|
|
Address string
|
|
|
|
TaggedAddresses map[string]string
|
2017-01-11 23:44:13 +00:00
|
|
|
NodeMeta map[string]string
|
2016-08-16 17:30:30 +00:00
|
|
|
Datacenter string
|
|
|
|
Service *AgentService
|
|
|
|
Check *AgentCheck
|
2018-10-29 16:39:25 +00:00
|
|
|
Checks HealthChecks
|
2017-10-20 20:39:13 +00:00
|
|
|
SkipNodeUpdate bool
|
2021-07-22 19:33:22 +00:00
|
|
|
Partition string `json:",omitempty"`
|
2015-01-06 18:40:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type CatalogDeregistration struct {
|
|
|
|
Node string
|
2019-12-06 20:47:41 +00:00
|
|
|
Address string `json:",omitempty"` // Obsolete.
|
2015-01-06 18:40:00 +00:00
|
|
|
Datacenter string
|
|
|
|
ServiceID string
|
|
|
|
CheckID string
|
2019-12-10 02:26:41 +00:00
|
|
|
Namespace string `json:",omitempty"`
|
2021-07-22 19:33:22 +00:00
|
|
|
Partition string `json:",omitempty"`
|
2015-01-06 18:40:00 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 19:01:45 +00:00
|
|
|
type CompoundServiceName struct {
|
|
|
|
Name string
|
|
|
|
|
|
|
|
// Namespacing is a Consul Enterprise feature.
|
|
|
|
Namespace string `json:",omitempty"`
|
2021-07-22 19:33:22 +00:00
|
|
|
// Partitions are a Consul Enterprise feature.
|
|
|
|
Partition string `json:",omitempty"`
|
2020-07-10 19:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GatewayService associates a gateway with a linked service.
|
|
|
|
// It also contains service-specific gateway configuration like ingress listener port and protocol.
|
|
|
|
type GatewayService struct {
|
|
|
|
Gateway CompoundServiceName
|
|
|
|
Service CompoundServiceName
|
|
|
|
GatewayKind ServiceKind
|
|
|
|
Port int `json:",omitempty"`
|
|
|
|
Protocol string `json:",omitempty"`
|
|
|
|
Hosts []string `json:",omitempty"`
|
|
|
|
CAFile string `json:",omitempty"`
|
|
|
|
CertFile string `json:",omitempty"`
|
|
|
|
KeyFile string `json:",omitempty"`
|
|
|
|
SNI string `json:",omitempty"`
|
|
|
|
FromWildcard bool `json:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
// Catalog can be used to query the Catalog endpoints
|
|
|
|
type Catalog struct {
|
|
|
|
c *Client
|
|
|
|
}
|
|
|
|
|
|
|
|
// Catalog returns a handle to the catalog endpoints
|
|
|
|
func (c *Client) Catalog() *Catalog {
|
|
|
|
return &Catalog{c}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Catalog) Register(reg *CatalogRegistration, q *WriteOptions) (*WriteMeta, error) {
|
|
|
|
r := c.c.newRequest("PUT", "/v1/catalog/register")
|
|
|
|
r.setWriteOptions(q)
|
|
|
|
r.obj = reg
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-10-28 16:24:23 +00:00
|
|
|
defer closeResponseBody(resp)
|
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
wm := &WriteMeta{}
|
|
|
|
wm.RequestTime = rtt
|
|
|
|
|
|
|
|
return wm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Catalog) Deregister(dereg *CatalogDeregistration, q *WriteOptions) (*WriteMeta, error) {
|
|
|
|
r := c.c.newRequest("PUT", "/v1/catalog/deregister")
|
|
|
|
r.setWriteOptions(q)
|
|
|
|
r.obj = dereg
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-10-28 16:24:23 +00:00
|
|
|
defer closeResponseBody(resp)
|
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
wm := &WriteMeta{}
|
|
|
|
wm.RequestTime = rtt
|
|
|
|
|
|
|
|
return wm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Datacenters is used to query for all the known datacenters
|
|
|
|
func (c *Catalog) Datacenters() ([]string, error) {
|
|
|
|
r := c.c.newRequest("GET", "/v1/catalog/datacenters")
|
2021-10-28 16:24:23 +00:00
|
|
|
_, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
var out []string
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nodes is used to query all the known nodes
|
|
|
|
func (c *Catalog) Nodes(q *QueryOptions) ([]*Node, *QueryMeta, error) {
|
|
|
|
r := c.c.newRequest("GET", "/v1/catalog/nodes")
|
|
|
|
r.setQueryOptions(q)
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
qm := &QueryMeta{}
|
|
|
|
parseQueryMeta(resp, qm)
|
|
|
|
qm.RequestTime = rtt
|
|
|
|
|
|
|
|
var out []*Node
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return out, qm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Services is used to query for all known services
|
|
|
|
func (c *Catalog) Services(q *QueryOptions) (map[string][]string, *QueryMeta, error) {
|
|
|
|
r := c.c.newRequest("GET", "/v1/catalog/services")
|
|
|
|
r.setQueryOptions(q)
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
qm := &QueryMeta{}
|
|
|
|
parseQueryMeta(resp, qm)
|
|
|
|
qm.RequestTime = rtt
|
|
|
|
|
|
|
|
var out map[string][]string
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return out, qm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Service is used to query catalog entries for a given service
|
|
|
|
func (c *Catalog) Service(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
2018-10-11 11:50:05 +00:00
|
|
|
var tags []string
|
|
|
|
if tag != "" {
|
|
|
|
tags = []string{tag}
|
|
|
|
}
|
|
|
|
return c.service(service, tags, q, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Supports multiple tags for filtering
|
|
|
|
func (c *Catalog) ServiceMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
|
|
|
return c.service(service, tags, q, false)
|
2018-03-26 15:51:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Connect is used to query catalog entries for a given Connect-enabled service
|
|
|
|
func (c *Catalog) Connect(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
2018-10-11 11:50:05 +00:00
|
|
|
var tags []string
|
|
|
|
if tag != "" {
|
|
|
|
tags = []string{tag}
|
|
|
|
}
|
|
|
|
return c.service(service, tags, q, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Supports multiple tags for filtering
|
|
|
|
func (c *Catalog) ConnectMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
|
|
|
return c.service(service, tags, q, true)
|
2018-03-26 15:51:43 +00:00
|
|
|
}
|
|
|
|
|
2018-10-11 11:50:05 +00:00
|
|
|
func (c *Catalog) service(service string, tags []string, q *QueryOptions, connect bool) ([]*CatalogService, *QueryMeta, error) {
|
2022-01-24 15:23:08 +00:00
|
|
|
path := "/v1/catalog/service/" + url.PathEscape(service)
|
2018-03-26 15:51:43 +00:00
|
|
|
if connect {
|
2022-01-24 15:23:08 +00:00
|
|
|
path = "/v1/catalog/connect/" + url.PathEscape(service)
|
2018-03-26 15:51:43 +00:00
|
|
|
}
|
|
|
|
r := c.c.newRequest("GET", path)
|
2015-01-06 18:40:00 +00:00
|
|
|
r.setQueryOptions(q)
|
2018-10-11 11:50:05 +00:00
|
|
|
if len(tags) > 0 {
|
|
|
|
for _, tag := range tags {
|
|
|
|
r.params.Add("tag", tag)
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
}
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
qm := &QueryMeta{}
|
|
|
|
parseQueryMeta(resp, qm)
|
|
|
|
qm.RequestTime = rtt
|
|
|
|
|
|
|
|
var out []*CatalogService
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return out, qm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Node is used to query for service information about a single node
|
|
|
|
func (c *Catalog) Node(node string, q *QueryOptions) (*CatalogNode, *QueryMeta, error) {
|
2022-01-24 15:23:08 +00:00
|
|
|
r := c.c.newRequest("GET", "/v1/catalog/node/"+url.PathEscape(node))
|
2015-01-06 18:40:00 +00:00
|
|
|
r.setQueryOptions(q)
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-06 18:40:00 +00:00
|
|
|
|
|
|
|
qm := &QueryMeta{}
|
|
|
|
parseQueryMeta(resp, qm)
|
|
|
|
qm.RequestTime = rtt
|
|
|
|
|
|
|
|
var out *CatalogNode
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return out, qm, nil
|
|
|
|
}
|
2019-06-17 14:51:50 +00:00
|
|
|
|
2020-01-24 14:27:25 +00:00
|
|
|
// NodeServiceList is used to query for service information about a single node. It differs from
|
|
|
|
// the Node function only in its return type which will contain a list of services as opposed to
|
|
|
|
// a map of service ids to services. This different structure allows for using the wildcard specifier
|
|
|
|
// '*' for the Namespace in the QueryOptions.
|
|
|
|
func (c *Catalog) NodeServiceList(node string, q *QueryOptions) (*CatalogNodeServiceList, *QueryMeta, error) {
|
2022-01-24 15:23:08 +00:00
|
|
|
r := c.c.newRequest("GET", "/v1/catalog/node-services/"+url.PathEscape(node))
|
2020-01-24 14:27:25 +00:00
|
|
|
r.setQueryOptions(q)
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2020-01-24 14:27:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-01-24 14:27:25 +00:00
|
|
|
|
|
|
|
qm := &QueryMeta{}
|
|
|
|
parseQueryMeta(resp, qm)
|
|
|
|
qm.RequestTime = rtt
|
|
|
|
|
|
|
|
var out *CatalogNodeServiceList
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return out, qm, nil
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:01:45 +00:00
|
|
|
// GatewayServices is used to query the services associated with an ingress gateway or terminating gateway.
|
|
|
|
func (c *Catalog) GatewayServices(gateway string, q *QueryOptions) ([]*GatewayService, *QueryMeta, error) {
|
2022-01-24 15:23:08 +00:00
|
|
|
r := c.c.newRequest("GET", "/v1/catalog/gateway-services/"+url.PathEscape(gateway))
|
2020-07-10 19:01:45 +00:00
|
|
|
r.setQueryOptions(q)
|
2021-10-28 16:24:23 +00:00
|
|
|
rtt, resp, err := c.c.doRequest(r)
|
2020-07-10 19:01:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2021-06-14 22:49:32 +00:00
|
|
|
defer closeResponseBody(resp)
|
2021-10-28 16:24:23 +00:00
|
|
|
if err := requireOK(resp); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-07-10 19:01:45 +00:00
|
|
|
|
|
|
|
qm := &QueryMeta{}
|
|
|
|
parseQueryMeta(resp, qm)
|
|
|
|
qm.RequestTime = rtt
|
|
|
|
|
|
|
|
var out []*GatewayService
|
|
|
|
if err := decodeBody(resp, &out); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return out, qm, nil
|
|
|
|
}
|
|
|
|
|
2019-06-17 14:51:50 +00:00
|
|
|
func ParseServiceAddr(addrPort string) (ServiceAddress, error) {
|
|
|
|
port := 0
|
|
|
|
host, portStr, err := net.SplitHostPort(addrPort)
|
|
|
|
if err == nil {
|
|
|
|
port, err = strconv.Atoi(portStr)
|
|
|
|
}
|
|
|
|
return ServiceAddress{Address: host, Port: port}, err
|
|
|
|
}
|