Add api mod support for /catalog/gateway-services (#8278)

This commit is contained in:
Freddy 2020-07-10 13:01:45 -06:00 committed by GitHub
parent 51f71d43ab
commit a30c10a18c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 195 additions and 61 deletions

View File

@ -1329,38 +1329,15 @@ func TestCatalog_GatewayServices_Terminating(t *testing.T) {
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
// Register a terminating gateway
args := &structs.RegisterRequest{
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)
// Register a service to be covered by the wildcard in the config entry
args := structs.TestRegisterRequest(t)
args.Service.Service = "redis"
args.Check = &structs.HealthCheck{
Name: "redis",
Status: api.HealthPassing,
ServiceID: args.Service.Service,
}
assert.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,
}
var out struct{}
assert.NoError(t, a.RPC("Catalog.Register", &args, &out))
// Associate the gateway and api/redis services
@ -1441,41 +1418,7 @@ func TestCatalog_GatewayServices_Ingress(t *testing.T) {
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
// Register an ingress gateway
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
// Associate an ingress gateway with api/redis
entryArgs := &structs.ConfigEntryRequest{
Op: structs.ConfigEntryUpsert,
Datacenter: "dc1",

View File

@ -81,6 +81,29 @@ type CatalogDeregistration struct {
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
type Catalog struct {
c *Client
@ -283,6 +306,27 @@ func (c *Catalog) NodeServiceList(node string, q *QueryOptions) (*CatalogNodeSer
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) {
port := 0
host, portStr, err := net.SplitHostPort(addrPort)

View File

@ -7,6 +7,7 @@ import (
"github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/stretchr/testify/assert"
"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)
})
}