mirror of https://github.com/hashicorp/consul
Add api mod support for /catalog/gateway-services (#8278)
parent
45a2987c6c
commit
e72af87918
|
@ -1329,38 +1329,15 @@ func TestCatalog_GatewayServices_Terminating(t *testing.T) {
|
||||||
|
|
||||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
// Register a terminating gateway
|
// Register a service to be covered by the wildcard in the config entry
|
||||||
args := &structs.RegisterRequest{
|
args := structs.TestRegisterRequest(t)
|
||||||
Datacenter: "dc1",
|
|
||||||
Node: "foo",
|
|
||||||
Address: "127.0.0.1",
|
|
||||||
Service: &structs.NodeService{
|
|
||||||
Kind: structs.ServiceKindTerminatingGateway,
|
|
||||||
Service: "terminating",
|
|
||||||
Port: 443,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var out struct{}
|
|
||||||
assert.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
|
||||||
|
|
||||||
// Register two services the gateway will route to
|
|
||||||
args = structs.TestRegisterRequest(t)
|
|
||||||
args.Service.Service = "redis"
|
args.Service.Service = "redis"
|
||||||
args.Check = &structs.HealthCheck{
|
args.Check = &structs.HealthCheck{
|
||||||
Name: "redis",
|
Name: "redis",
|
||||||
Status: api.HealthPassing,
|
Status: api.HealthPassing,
|
||||||
ServiceID: args.Service.Service,
|
ServiceID: args.Service.Service,
|
||||||
}
|
}
|
||||||
assert.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
var out struct{}
|
||||||
|
|
||||||
args = structs.TestRegisterRequest(t)
|
|
||||||
args.Service.Service = "api"
|
|
||||||
args.Check = &structs.HealthCheck{
|
|
||||||
Name: "api",
|
|
||||||
Status: api.HealthPassing,
|
|
||||||
ServiceID: args.Service.Service,
|
|
||||||
}
|
|
||||||
assert.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
assert.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
||||||
|
|
||||||
// Associate the gateway and api/redis services
|
// Associate the gateway and api/redis services
|
||||||
|
@ -1441,41 +1418,7 @@ func TestCatalog_GatewayServices_Ingress(t *testing.T) {
|
||||||
|
|
||||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
// Register an ingress gateway
|
// Associate an ingress gateway with api/redis
|
||||||
args := &structs.RegisterRequest{
|
|
||||||
Datacenter: "dc1",
|
|
||||||
Node: "foo",
|
|
||||||
Address: "127.0.0.1",
|
|
||||||
Service: &structs.NodeService{
|
|
||||||
Kind: structs.ServiceKindTerminatingGateway,
|
|
||||||
Service: "ingress",
|
|
||||||
Port: 444,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var out struct{}
|
|
||||||
require.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
|
||||||
|
|
||||||
// Register two services the gateway will route to
|
|
||||||
args = structs.TestRegisterRequest(t)
|
|
||||||
args.Service.Service = "redis"
|
|
||||||
args.Check = &structs.HealthCheck{
|
|
||||||
Name: "redis",
|
|
||||||
Status: api.HealthPassing,
|
|
||||||
ServiceID: args.Service.Service,
|
|
||||||
}
|
|
||||||
require.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
|
||||||
|
|
||||||
args = structs.TestRegisterRequest(t)
|
|
||||||
args.Service.Service = "api"
|
|
||||||
args.Check = &structs.HealthCheck{
|
|
||||||
Name: "api",
|
|
||||||
Status: api.HealthPassing,
|
|
||||||
ServiceID: args.Service.Service,
|
|
||||||
}
|
|
||||||
require.NoError(t, a.RPC("Catalog.Register", &args, &out))
|
|
||||||
|
|
||||||
// Associate the gateway and db service
|
|
||||||
entryArgs := &structs.ConfigEntryRequest{
|
entryArgs := &structs.ConfigEntryRequest{
|
||||||
Op: structs.ConfigEntryUpsert,
|
Op: structs.ConfigEntryUpsert,
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
|
|
|
@ -81,6 +81,29 @@ type CatalogDeregistration struct {
|
||||||
Namespace string `json:",omitempty"`
|
Namespace string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CompoundServiceName struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Namespacing is a Consul Enterprise feature.
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
// Catalog can be used to query the Catalog endpoints
|
// Catalog can be used to query the Catalog endpoints
|
||||||
type Catalog struct {
|
type Catalog struct {
|
||||||
c *Client
|
c *Client
|
||||||
|
@ -283,6 +306,27 @@ func (c *Catalog) NodeServiceList(node string, q *QueryOptions) (*CatalogNodeSer
|
||||||
return out, qm, nil
|
return out, qm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/gateway-services/"+gateway)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
func ParseServiceAddr(addrPort string) (ServiceAddress, error) {
|
func ParseServiceAddr(addrPort string) (ServiceAddress, error) {
|
||||||
port := 0
|
port := 0
|
||||||
host, portStr, err := net.SplitHostPort(addrPort)
|
host, portStr, err := net.SplitHostPort(addrPort)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/consul/sdk/testutil"
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
"github.com/hashicorp/consul/sdk/testutil/retry"
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1088,3 +1089,149 @@ func TestAPI_CatalogEnableTagOverride(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPI_CatalogGatewayServices_Terminating(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c, s := makeClient(t)
|
||||||
|
defer s.Stop()
|
||||||
|
s.WaitForSerfCheck(t)
|
||||||
|
|
||||||
|
catalog := c.Catalog()
|
||||||
|
|
||||||
|
// Register a service to be covered by a wildcard in the config entry
|
||||||
|
svc := &AgentService{
|
||||||
|
ID: "redis",
|
||||||
|
Service: "redis",
|
||||||
|
Port: 6379,
|
||||||
|
}
|
||||||
|
reg := &CatalogRegistration{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Node: "bar",
|
||||||
|
Address: "192.168.10.11",
|
||||||
|
Service: svc,
|
||||||
|
}
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
if _, err := catalog.Register(reg, nil); err != nil {
|
||||||
|
r.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
entries := c.ConfigEntries()
|
||||||
|
|
||||||
|
// Associate the gateway and api/redis services
|
||||||
|
gwEntry := TerminatingGatewayConfigEntry{
|
||||||
|
Kind: TerminatingGateway,
|
||||||
|
Name: "terminating",
|
||||||
|
Services: []LinkedService{
|
||||||
|
{
|
||||||
|
Name: "api",
|
||||||
|
CAFile: "api/ca.crt",
|
||||||
|
CertFile: "api/client.crt",
|
||||||
|
KeyFile: "api/client.key",
|
||||||
|
SNI: "my-domain",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "*",
|
||||||
|
CAFile: "ca.crt",
|
||||||
|
CertFile: "client.crt",
|
||||||
|
KeyFile: "client.key",
|
||||||
|
SNI: "my-alt-domain",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
if success, _, err := entries.Set(&gwEntry, nil); err != nil || !success {
|
||||||
|
r.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect := []*GatewayService{
|
||||||
|
{
|
||||||
|
Service: CompoundServiceName{"api", defaultNamespace},
|
||||||
|
Gateway: CompoundServiceName{"terminating", defaultNamespace},
|
||||||
|
GatewayKind: ServiceKindTerminatingGateway,
|
||||||
|
CAFile: "api/ca.crt",
|
||||||
|
CertFile: "api/client.crt",
|
||||||
|
KeyFile: "api/client.key",
|
||||||
|
SNI: "my-domain",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Service: CompoundServiceName{"redis", defaultNamespace},
|
||||||
|
Gateway: CompoundServiceName{"terminating", defaultNamespace},
|
||||||
|
GatewayKind: ServiceKindTerminatingGateway,
|
||||||
|
CAFile: "ca.crt",
|
||||||
|
CertFile: "client.crt",
|
||||||
|
KeyFile: "client.key",
|
||||||
|
SNI: "my-alt-domain",
|
||||||
|
FromWildcard: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
resp, _, err := catalog.GatewayServices("terminating", nil)
|
||||||
|
assert.NoError(r, err)
|
||||||
|
assert.Equal(r, expect, resp)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPI_CatalogGatewayServices_Ingress(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c, s := makeClient(t)
|
||||||
|
defer s.Stop()
|
||||||
|
|
||||||
|
s.WaitForSerfCheck(t)
|
||||||
|
|
||||||
|
entries := c.ConfigEntries()
|
||||||
|
|
||||||
|
// Associate the gateway and api/redis services
|
||||||
|
gwEntry := IngressGatewayConfigEntry{
|
||||||
|
Kind: "ingress-gateway",
|
||||||
|
Name: "ingress",
|
||||||
|
Listeners: []IngressListener{
|
||||||
|
{
|
||||||
|
Port: 8888,
|
||||||
|
Services: []IngressService{
|
||||||
|
{
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Port: 9999,
|
||||||
|
Services: []IngressService{
|
||||||
|
{
|
||||||
|
Name: "redis",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
if success, _, err := entries.Set(&gwEntry, nil); err != nil || !success {
|
||||||
|
r.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
catalog := c.Catalog()
|
||||||
|
|
||||||
|
expect := []*GatewayService{
|
||||||
|
{
|
||||||
|
Service: CompoundServiceName{"api", defaultNamespace},
|
||||||
|
Gateway: CompoundServiceName{"ingress", defaultNamespace},
|
||||||
|
GatewayKind: ServiceKindIngressGateway,
|
||||||
|
Protocol: "tcp",
|
||||||
|
Port: 8888,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Service: CompoundServiceName{"redis", defaultNamespace},
|
||||||
|
Gateway: CompoundServiceName{"ingress", defaultNamespace},
|
||||||
|
GatewayKind: ServiceKindIngressGateway,
|
||||||
|
Protocol: "tcp",
|
||||||
|
Port: 9999,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
resp, _, err := catalog.GatewayServices("ingress", nil)
|
||||||
|
assert.NoError(r, err)
|
||||||
|
assert.Equal(r, expect, resp)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue