mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
api: move serviceregistration client to servics to match CLI.
The service registration client name was used to provide a distinction between the service block and the service client. This however creates new wording to understand and does not match the CLI, therefore this change fixes that so we have a Services client. Consul specific objects within the service file have been moved to the consul location to create a clearer separation.
This commit is contained in:
557
api/consul.go
557
api/consul.go
@@ -1,5 +1,7 @@
|
||||
package api
|
||||
|
||||
import "time"
|
||||
|
||||
// Consul represents configuration related to consul.
|
||||
type Consul struct {
|
||||
// (Enterprise-only) Namespace represents a Consul namespace.
|
||||
@@ -33,3 +35,558 @@ func (c *Consul) MergeNamespace(namespace *string) {
|
||||
c.Namespace = *namespace
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulConnect represents a Consul Connect jobspec stanza.
|
||||
type ConsulConnect struct {
|
||||
Native bool `hcl:"native,optional"`
|
||||
Gateway *ConsulGateway `hcl:"gateway,block"`
|
||||
SidecarService *ConsulSidecarService `mapstructure:"sidecar_service" hcl:"sidecar_service,block"`
|
||||
SidecarTask *SidecarTask `mapstructure:"sidecar_task" hcl:"sidecar_task,block"`
|
||||
}
|
||||
|
||||
func (cc *ConsulConnect) Canonicalize() {
|
||||
if cc == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cc.SidecarService.Canonicalize()
|
||||
cc.SidecarTask.Canonicalize()
|
||||
cc.Gateway.Canonicalize()
|
||||
}
|
||||
|
||||
// ConsulSidecarService represents a Consul Connect SidecarService jobspec
|
||||
// stanza.
|
||||
type ConsulSidecarService struct {
|
||||
Tags []string `hcl:"tags,optional"`
|
||||
Port string `hcl:"port,optional"`
|
||||
Proxy *ConsulProxy `hcl:"proxy,block"`
|
||||
DisableDefaultTCPCheck bool `mapstructure:"disable_default_tcp_check" hcl:"disable_default_tcp_check,optional"`
|
||||
}
|
||||
|
||||
func (css *ConsulSidecarService) Canonicalize() {
|
||||
if css == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(css.Tags) == 0 {
|
||||
css.Tags = nil
|
||||
}
|
||||
|
||||
css.Proxy.Canonicalize()
|
||||
}
|
||||
|
||||
|
||||
// SidecarTask represents a subset of Task fields that can be set to override
|
||||
// the fields of the Task generated for the sidecar
|
||||
type SidecarTask struct {
|
||||
Name string `hcl:"name,optional"`
|
||||
Driver string `hcl:"driver,optional"`
|
||||
User string `hcl:"user,optional"`
|
||||
Config map[string]interface{} `hcl:"config,block"`
|
||||
Env map[string]string `hcl:"env,block"`
|
||||
Resources *Resources `hcl:"resources,block"`
|
||||
Meta map[string]string `hcl:"meta,block"`
|
||||
KillTimeout *time.Duration `mapstructure:"kill_timeout" hcl:"kill_timeout,optional"`
|
||||
LogConfig *LogConfig `mapstructure:"logs" hcl:"logs,block"`
|
||||
ShutdownDelay *time.Duration `mapstructure:"shutdown_delay" hcl:"shutdown_delay,optional"`
|
||||
KillSignal string `mapstructure:"kill_signal" hcl:"kill_signal,optional"`
|
||||
}
|
||||
|
||||
func (st *SidecarTask) Canonicalize() {
|
||||
if st == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(st.Config) == 0 {
|
||||
st.Config = nil
|
||||
}
|
||||
|
||||
if len(st.Env) == 0 {
|
||||
st.Env = nil
|
||||
}
|
||||
|
||||
if st.Resources == nil {
|
||||
st.Resources = DefaultResources()
|
||||
} else {
|
||||
st.Resources.Canonicalize()
|
||||
}
|
||||
|
||||
if st.LogConfig == nil {
|
||||
st.LogConfig = DefaultLogConfig()
|
||||
} else {
|
||||
st.LogConfig.Canonicalize()
|
||||
}
|
||||
|
||||
if len(st.Meta) == 0 {
|
||||
st.Meta = nil
|
||||
}
|
||||
|
||||
if st.KillTimeout == nil {
|
||||
st.KillTimeout = timeToPtr(5 * time.Second)
|
||||
}
|
||||
|
||||
if st.ShutdownDelay == nil {
|
||||
st.ShutdownDelay = timeToPtr(0)
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulProxy represents a Consul Connect sidecar proxy jobspec stanza.
|
||||
type ConsulProxy struct {
|
||||
LocalServiceAddress string `mapstructure:"local_service_address" hcl:"local_service_address,optional"`
|
||||
LocalServicePort int `mapstructure:"local_service_port" hcl:"local_service_port,optional"`
|
||||
ExposeConfig *ConsulExposeConfig `mapstructure:"expose" hcl:"expose,block"`
|
||||
Upstreams []*ConsulUpstream `hcl:"upstreams,block"`
|
||||
Config map[string]interface{} `hcl:"config,block"`
|
||||
}
|
||||
|
||||
func (cp *ConsulProxy) Canonicalize() {
|
||||
if cp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cp.ExposeConfig.Canonicalize()
|
||||
|
||||
if len(cp.Upstreams) == 0 {
|
||||
cp.Upstreams = nil
|
||||
}
|
||||
|
||||
for _, upstream := range cp.Upstreams {
|
||||
upstream.Canonicalize()
|
||||
}
|
||||
|
||||
if len(cp.Config) == 0 {
|
||||
cp.Config = nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulMeshGateway is used to configure mesh gateway usage when connecting to
|
||||
// a connect upstream in another datacenter.
|
||||
type ConsulMeshGateway struct {
|
||||
// Mode configures how an upstream should be accessed with regard to using
|
||||
// mesh gateways.
|
||||
//
|
||||
// local - the connect proxy makes outbound connections through mesh gateway
|
||||
// originating in the same datacenter.
|
||||
//
|
||||
// remote - the connect proxy makes outbound connections to a mesh gateway
|
||||
// in the destination datacenter.
|
||||
//
|
||||
// none (default) - no mesh gateway is used, the proxy makes outbound connections
|
||||
// directly to destination services.
|
||||
//
|
||||
// https://www.consul.io/docs/connect/gateways/mesh-gateway#modes-of-operation
|
||||
Mode string `mapstructure:"mode" hcl:"mode,optional"`
|
||||
}
|
||||
|
||||
func (c *ConsulMeshGateway) Canonicalize() {
|
||||
// Mode may be empty string, indicating behavior will defer to Consul
|
||||
// service-defaults config entry.
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ConsulMeshGateway) Copy() *ConsulMeshGateway {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulMeshGateway{
|
||||
Mode: c.Mode,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulUpstream represents a Consul Connect upstream jobspec stanza.
|
||||
type ConsulUpstream struct {
|
||||
DestinationName string `mapstructure:"destination_name" hcl:"destination_name,optional"`
|
||||
LocalBindPort int `mapstructure:"local_bind_port" hcl:"local_bind_port,optional"`
|
||||
Datacenter string `mapstructure:"datacenter" hcl:"datacenter,optional"`
|
||||
LocalBindAddress string `mapstructure:"local_bind_address" hcl:"local_bind_address,optional"`
|
||||
MeshGateway *ConsulMeshGateway `mapstructure:"mesh_gateway" hcl:"mesh_gateway,block"`
|
||||
}
|
||||
|
||||
func (cu *ConsulUpstream) Copy() *ConsulUpstream {
|
||||
if cu == nil {
|
||||
return nil
|
||||
}
|
||||
return &ConsulUpstream{
|
||||
DestinationName: cu.DestinationName,
|
||||
LocalBindPort: cu.LocalBindPort,
|
||||
Datacenter: cu.Datacenter,
|
||||
LocalBindAddress: cu.LocalBindAddress,
|
||||
MeshGateway: cu.MeshGateway.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
func (cu *ConsulUpstream) Canonicalize() {
|
||||
if cu == nil {
|
||||
return
|
||||
}
|
||||
cu.MeshGateway.Canonicalize()
|
||||
}
|
||||
|
||||
type ConsulExposeConfig struct {
|
||||
Path []*ConsulExposePath `mapstructure:"path" hcl:"path,block"`
|
||||
}
|
||||
|
||||
func (cec *ConsulExposeConfig) Canonicalize() {
|
||||
if cec == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(cec.Path) == 0 {
|
||||
cec.Path = nil
|
||||
}
|
||||
}
|
||||
|
||||
type ConsulExposePath struct {
|
||||
Path string `hcl:"path,optional"`
|
||||
Protocol string `hcl:"protocol,optional"`
|
||||
LocalPathPort int `mapstructure:"local_path_port" hcl:"local_path_port,optional"`
|
||||
ListenerPort string `mapstructure:"listener_port" hcl:"listener_port,optional"`
|
||||
}
|
||||
|
||||
// ConsulGateway is used to configure one of the Consul Connect Gateway types.
|
||||
type ConsulGateway struct {
|
||||
// Proxy is used to configure the Envoy instance acting as the gateway.
|
||||
Proxy *ConsulGatewayProxy `hcl:"proxy,block"`
|
||||
|
||||
// Ingress represents the Consul Configuration Entry for an Ingress Gateway.
|
||||
Ingress *ConsulIngressConfigEntry `hcl:"ingress,block"`
|
||||
|
||||
// Terminating represents the Consul Configuration Entry for a Terminating Gateway.
|
||||
Terminating *ConsulTerminatingConfigEntry `hcl:"terminating,block"`
|
||||
|
||||
// Mesh indicates the Consul service should be a Mesh Gateway.
|
||||
Mesh *ConsulMeshConfigEntry `hcl:"mesh,block"`
|
||||
}
|
||||
|
||||
func (g *ConsulGateway) Canonicalize() {
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
g.Proxy.Canonicalize()
|
||||
g.Ingress.Canonicalize()
|
||||
g.Terminating.Canonicalize()
|
||||
}
|
||||
|
||||
func (g *ConsulGateway) Copy() *ConsulGateway {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulGateway{
|
||||
Proxy: g.Proxy.Copy(),
|
||||
Ingress: g.Ingress.Copy(),
|
||||
Terminating: g.Terminating.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
type ConsulGatewayBindAddress struct {
|
||||
Name string `hcl:",label"`
|
||||
Address string `mapstructure:"address" hcl:"address,optional"`
|
||||
Port int `mapstructure:"port" hcl:"port,optional"`
|
||||
}
|
||||
|
||||
var (
|
||||
// defaultGatewayConnectTimeout is the default amount of time connections to
|
||||
// upstreams are allowed before timing out.
|
||||
defaultGatewayConnectTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// ConsulGatewayProxy is used to tune parameters of the proxy instance acting as
|
||||
// one of the forms of Connect gateways that Consul supports.
|
||||
//
|
||||
// https://www.consul.io/docs/connect/proxies/envoy#gateway-options
|
||||
type ConsulGatewayProxy struct {
|
||||
ConnectTimeout *time.Duration `mapstructure:"connect_timeout" hcl:"connect_timeout,optional"`
|
||||
EnvoyGatewayBindTaggedAddresses bool `mapstructure:"envoy_gateway_bind_tagged_addresses" hcl:"envoy_gateway_bind_tagged_addresses,optional"`
|
||||
EnvoyGatewayBindAddresses map[string]*ConsulGatewayBindAddress `mapstructure:"envoy_gateway_bind_addresses" hcl:"envoy_gateway_bind_addresses,block"`
|
||||
EnvoyGatewayNoDefaultBind bool `mapstructure:"envoy_gateway_no_default_bind" hcl:"envoy_gateway_no_default_bind,optional"`
|
||||
EnvoyDNSDiscoveryType string `mapstructure:"envoy_dns_discovery_type" hcl:"envoy_dns_discovery_type,optional"`
|
||||
Config map[string]interface{} `hcl:"config,block"` // escape hatch envoy config
|
||||
}
|
||||
|
||||
func (p *ConsulGatewayProxy) Canonicalize() {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if p.ConnectTimeout == nil {
|
||||
// same as the default from consul
|
||||
p.ConnectTimeout = timeToPtr(defaultGatewayConnectTimeout)
|
||||
}
|
||||
|
||||
if len(p.EnvoyGatewayBindAddresses) == 0 {
|
||||
p.EnvoyGatewayBindAddresses = nil
|
||||
}
|
||||
|
||||
if len(p.Config) == 0 {
|
||||
p.Config = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ConsulGatewayProxy) Copy() *ConsulGatewayProxy {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var binds map[string]*ConsulGatewayBindAddress = nil
|
||||
if p.EnvoyGatewayBindAddresses != nil {
|
||||
binds = make(map[string]*ConsulGatewayBindAddress, len(p.EnvoyGatewayBindAddresses))
|
||||
for k, v := range p.EnvoyGatewayBindAddresses {
|
||||
binds[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
var config map[string]interface{} = nil
|
||||
if p.Config != nil {
|
||||
config = make(map[string]interface{}, len(p.Config))
|
||||
for k, v := range p.Config {
|
||||
config[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulGatewayProxy{
|
||||
ConnectTimeout: timeToPtr(*p.ConnectTimeout),
|
||||
EnvoyGatewayBindTaggedAddresses: p.EnvoyGatewayBindTaggedAddresses,
|
||||
EnvoyGatewayBindAddresses: binds,
|
||||
EnvoyGatewayNoDefaultBind: p.EnvoyGatewayNoDefaultBind,
|
||||
EnvoyDNSDiscoveryType: p.EnvoyDNSDiscoveryType,
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulGatewayTLSConfig is used to configure TLS for a gateway.
|
||||
type ConsulGatewayTLSConfig struct {
|
||||
Enabled bool `hcl:"enabled,optional"`
|
||||
}
|
||||
|
||||
func (tc *ConsulGatewayTLSConfig) Canonicalize() {
|
||||
}
|
||||
|
||||
func (tc *ConsulGatewayTLSConfig) Copy() *ConsulGatewayTLSConfig {
|
||||
if tc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulGatewayTLSConfig{
|
||||
Enabled: tc.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulIngressService is used to configure a service fronted by the ingress gateway.
|
||||
type ConsulIngressService struct {
|
||||
// Namespace is not yet supported.
|
||||
// Namespace string
|
||||
Name string `hcl:"name,optional"`
|
||||
|
||||
Hosts []string `hcl:"hosts,optional"`
|
||||
}
|
||||
|
||||
func (s *ConsulIngressService) Canonicalize() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(s.Hosts) == 0 {
|
||||
s.Hosts = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConsulIngressService) Copy() *ConsulIngressService {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var hosts []string = nil
|
||||
if n := len(s.Hosts); n > 0 {
|
||||
hosts = make([]string, n)
|
||||
copy(hosts, s.Hosts)
|
||||
}
|
||||
|
||||
return &ConsulIngressService{
|
||||
Name: s.Name,
|
||||
Hosts: hosts,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
defaultIngressListenerProtocol = "tcp"
|
||||
)
|
||||
|
||||
// ConsulIngressListener is used to configure a listener on a Consul Ingress
|
||||
// Gateway.
|
||||
type ConsulIngressListener struct {
|
||||
Port int `hcl:"port,optional"`
|
||||
Protocol string `hcl:"protocol,optional"`
|
||||
Services []*ConsulIngressService `hcl:"service,block"`
|
||||
}
|
||||
|
||||
func (l *ConsulIngressListener) Canonicalize() {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if l.Protocol == "" {
|
||||
// same as default from consul
|
||||
l.Protocol = defaultIngressListenerProtocol
|
||||
}
|
||||
|
||||
if len(l.Services) == 0 {
|
||||
l.Services = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ConsulIngressListener) Copy() *ConsulIngressListener {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var services []*ConsulIngressService = nil
|
||||
if n := len(l.Services); n > 0 {
|
||||
services = make([]*ConsulIngressService, n)
|
||||
for i := 0; i < n; i++ {
|
||||
services[i] = l.Services[i].Copy()
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulIngressListener{
|
||||
Port: l.Port,
|
||||
Protocol: l.Protocol,
|
||||
Services: services,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulIngressConfigEntry represents the Consul Configuration Entry type for
|
||||
// an Ingress Gateway.
|
||||
//
|
||||
// https://www.consul.io/docs/agent/config-entries/ingress-gateway#available-fields
|
||||
type ConsulIngressConfigEntry struct {
|
||||
// Namespace is not yet supported.
|
||||
// Namespace string
|
||||
|
||||
TLS *ConsulGatewayTLSConfig `hcl:"tls,block"`
|
||||
Listeners []*ConsulIngressListener `hcl:"listener,block"`
|
||||
}
|
||||
|
||||
func (e *ConsulIngressConfigEntry) Canonicalize() {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
|
||||
e.TLS.Canonicalize()
|
||||
|
||||
if len(e.Listeners) == 0 {
|
||||
e.Listeners = nil
|
||||
}
|
||||
|
||||
for _, listener := range e.Listeners {
|
||||
listener.Canonicalize()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ConsulIngressConfigEntry) Copy() *ConsulIngressConfigEntry {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var listeners []*ConsulIngressListener = nil
|
||||
if n := len(e.Listeners); n > 0 {
|
||||
listeners = make([]*ConsulIngressListener, n)
|
||||
for i := 0; i < n; i++ {
|
||||
listeners[i] = e.Listeners[i].Copy()
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulIngressConfigEntry{
|
||||
TLS: e.TLS.Copy(),
|
||||
Listeners: listeners,
|
||||
}
|
||||
}
|
||||
|
||||
type ConsulLinkedService struct {
|
||||
Name string `hcl:"name,optional"`
|
||||
CAFile string `hcl:"ca_file,optional" mapstructure:"ca_file"`
|
||||
CertFile string `hcl:"cert_file,optional" mapstructure:"cert_file"`
|
||||
KeyFile string `hcl:"key_file,optional" mapstructure:"key_file"`
|
||||
SNI string `hcl:"sni,optional"`
|
||||
}
|
||||
|
||||
func (s *ConsulLinkedService) Canonicalize() {
|
||||
// nothing to do for now
|
||||
}
|
||||
|
||||
func (s *ConsulLinkedService) Copy() *ConsulLinkedService {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulLinkedService{
|
||||
Name: s.Name,
|
||||
CAFile: s.CAFile,
|
||||
CertFile: s.CertFile,
|
||||
KeyFile: s.KeyFile,
|
||||
SNI: s.SNI,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulTerminatingConfigEntry represents the Consul Configuration Entry type
|
||||
// for a Terminating Gateway.
|
||||
//
|
||||
// https://www.consul.io/docs/agent/config-entries/terminating-gateway#available-fields
|
||||
type ConsulTerminatingConfigEntry struct {
|
||||
// Namespace is not yet supported.
|
||||
// Namespace string
|
||||
|
||||
Services []*ConsulLinkedService `hcl:"service,block"`
|
||||
}
|
||||
|
||||
func (e *ConsulTerminatingConfigEntry) Canonicalize() {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(e.Services) == 0 {
|
||||
e.Services = nil
|
||||
}
|
||||
|
||||
for _, service := range e.Services {
|
||||
service.Canonicalize()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ConsulTerminatingConfigEntry) Copy() *ConsulTerminatingConfigEntry {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var services []*ConsulLinkedService = nil
|
||||
if n := len(e.Services); n > 0 {
|
||||
services = make([]*ConsulLinkedService, n)
|
||||
for i := 0; i < n; i++ {
|
||||
services[i] = e.Services[i].Copy()
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulTerminatingConfigEntry{
|
||||
Services: services,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulMeshConfigEntry is a stub used to represent that the gateway service type
|
||||
// should be for a Mesh Gateway. Unlike Ingress and Terminating, there is no
|
||||
// actual Consul Config Entry type for mesh-gateway, at least for now. We still
|
||||
// create a type for future proofing, instead just using a bool for example.
|
||||
type ConsulMeshConfigEntry struct {
|
||||
// nothing in here
|
||||
}
|
||||
|
||||
func (e *ConsulMeshConfigEntry) Canonicalize() {
|
||||
return
|
||||
}
|
||||
|
||||
func (e *ConsulMeshConfigEntry) Copy() *ConsulMeshConfigEntry {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return new(ConsulMeshConfigEntry)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/api/internal/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -60,3 +61,455 @@ func TestConsul_MergeNamespace(t *testing.T) {
|
||||
require.Nil(t, ns)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulConnect_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil connect", func(t *testing.T) {
|
||||
cc := (*ConsulConnect)(nil)
|
||||
cc.Canonicalize()
|
||||
require.Nil(t, cc)
|
||||
})
|
||||
|
||||
t.Run("empty connect", func(t *testing.T) {
|
||||
cc := new(ConsulConnect)
|
||||
cc.Canonicalize()
|
||||
require.Empty(t, cc.Native)
|
||||
require.Nil(t, cc.SidecarService)
|
||||
require.Nil(t, cc.SidecarTask)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulSidecarService_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil sidecar_service", func(t *testing.T) {
|
||||
css := (*ConsulSidecarService)(nil)
|
||||
css.Canonicalize()
|
||||
require.Nil(t, css)
|
||||
})
|
||||
|
||||
t.Run("empty sidecar_service", func(t *testing.T) {
|
||||
css := new(ConsulSidecarService)
|
||||
css.Canonicalize()
|
||||
require.Empty(t, css.Tags)
|
||||
require.Nil(t, css.Proxy)
|
||||
})
|
||||
|
||||
t.Run("non-empty sidecar_service", func(t *testing.T) {
|
||||
css := &ConsulSidecarService{
|
||||
Tags: make([]string, 0),
|
||||
Port: "port",
|
||||
Proxy: &ConsulProxy{
|
||||
LocalServiceAddress: "lsa",
|
||||
LocalServicePort: 80,
|
||||
},
|
||||
}
|
||||
css.Canonicalize()
|
||||
require.Equal(t, &ConsulSidecarService{
|
||||
Tags: nil,
|
||||
Port: "port",
|
||||
Proxy: &ConsulProxy{
|
||||
LocalServiceAddress: "lsa",
|
||||
LocalServicePort: 80},
|
||||
}, css)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulProxy_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil proxy", func(t *testing.T) {
|
||||
cp := (*ConsulProxy)(nil)
|
||||
cp.Canonicalize()
|
||||
require.Nil(t, cp)
|
||||
})
|
||||
|
||||
t.Run("empty proxy", func(t *testing.T) {
|
||||
cp := new(ConsulProxy)
|
||||
cp.Canonicalize()
|
||||
require.Empty(t, cp.LocalServiceAddress)
|
||||
require.Zero(t, cp.LocalServicePort)
|
||||
require.Nil(t, cp.ExposeConfig)
|
||||
require.Nil(t, cp.Upstreams)
|
||||
require.Empty(t, cp.Config)
|
||||
})
|
||||
|
||||
t.Run("non empty proxy", func(t *testing.T) {
|
||||
cp := &ConsulProxy{
|
||||
LocalServiceAddress: "127.0.0.1",
|
||||
LocalServicePort: 80,
|
||||
ExposeConfig: new(ConsulExposeConfig),
|
||||
Upstreams: make([]*ConsulUpstream, 0),
|
||||
Config: make(map[string]interface{}),
|
||||
}
|
||||
cp.Canonicalize()
|
||||
require.Equal(t, "127.0.0.1", cp.LocalServiceAddress)
|
||||
require.Equal(t, 80, cp.LocalServicePort)
|
||||
require.Equal(t, &ConsulExposeConfig{}, cp.ExposeConfig)
|
||||
require.Nil(t, cp.Upstreams)
|
||||
require.Nil(t, cp.Config)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulUpstream_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil upstream", func(t *testing.T) {
|
||||
cu := (*ConsulUpstream)(nil)
|
||||
result := cu.Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
t.Run("complete upstream", func(t *testing.T) {
|
||||
cu := &ConsulUpstream{
|
||||
DestinationName: "dest1",
|
||||
Datacenter: "dc2",
|
||||
LocalBindPort: 2000,
|
||||
LocalBindAddress: "10.0.0.1",
|
||||
MeshGateway: &ConsulMeshGateway{Mode: "remote"},
|
||||
}
|
||||
result := cu.Copy()
|
||||
require.Equal(t, cu, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulUpstream_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil upstream", func(t *testing.T) {
|
||||
cu := (*ConsulUpstream)(nil)
|
||||
cu.Canonicalize()
|
||||
require.Nil(t, cu)
|
||||
})
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
cu := &ConsulUpstream{
|
||||
DestinationName: "dest1",
|
||||
Datacenter: "dc2",
|
||||
LocalBindPort: 2000,
|
||||
LocalBindAddress: "10.0.0.1",
|
||||
MeshGateway: &ConsulMeshGateway{Mode: ""},
|
||||
}
|
||||
cu.Canonicalize()
|
||||
require.Equal(t, &ConsulUpstream{
|
||||
DestinationName: "dest1",
|
||||
Datacenter: "dc2",
|
||||
LocalBindPort: 2000,
|
||||
LocalBindAddress: "10.0.0.1",
|
||||
MeshGateway: &ConsulMeshGateway{Mode: ""},
|
||||
}, cu)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSidecarTask_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil sidecar_task", func(t *testing.T) {
|
||||
st := (*SidecarTask)(nil)
|
||||
st.Canonicalize()
|
||||
require.Nil(t, st)
|
||||
})
|
||||
|
||||
t.Run("empty sidecar_task", func(t *testing.T) {
|
||||
st := new(SidecarTask)
|
||||
st.Canonicalize()
|
||||
require.Nil(t, st.Config)
|
||||
require.Nil(t, st.Env)
|
||||
require.Equal(t, DefaultResources(), st.Resources)
|
||||
require.Equal(t, DefaultLogConfig(), st.LogConfig)
|
||||
require.Nil(t, st.Meta)
|
||||
require.Equal(t, 5*time.Second, *st.KillTimeout)
|
||||
require.Equal(t, 0*time.Second, *st.ShutdownDelay)
|
||||
})
|
||||
|
||||
t.Run("non empty sidecar_task resources", func(t *testing.T) {
|
||||
exp := DefaultResources()
|
||||
exp.MemoryMB = intToPtr(333)
|
||||
st := &SidecarTask{
|
||||
Resources: &Resources{MemoryMB: intToPtr(333)},
|
||||
}
|
||||
st.Canonicalize()
|
||||
require.Equal(t, exp, st.Resources)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulGateway_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
cg := (*ConsulGateway)(nil)
|
||||
cg.Canonicalize()
|
||||
require.Nil(t, cg)
|
||||
})
|
||||
|
||||
t.Run("set defaults", func(t *testing.T) {
|
||||
cg := &ConsulGateway{
|
||||
Proxy: &ConsulGatewayProxy{
|
||||
ConnectTimeout: nil,
|
||||
EnvoyGatewayBindTaggedAddresses: true,
|
||||
EnvoyGatewayBindAddresses: make(map[string]*ConsulGatewayBindAddress, 0),
|
||||
EnvoyGatewayNoDefaultBind: true,
|
||||
Config: make(map[string]interface{}, 0),
|
||||
},
|
||||
Ingress: &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
Listeners: make([]*ConsulIngressListener, 0),
|
||||
},
|
||||
}
|
||||
cg.Canonicalize()
|
||||
require.Equal(t, timeToPtr(5*time.Second), cg.Proxy.ConnectTimeout)
|
||||
require.True(t, cg.Proxy.EnvoyGatewayBindTaggedAddresses)
|
||||
require.Nil(t, cg.Proxy.EnvoyGatewayBindAddresses)
|
||||
require.True(t, cg.Proxy.EnvoyGatewayNoDefaultBind)
|
||||
require.Empty(t, cg.Proxy.EnvoyDNSDiscoveryType)
|
||||
require.Nil(t, cg.Proxy.Config)
|
||||
require.Nil(t, cg.Ingress.Listeners)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulGateway_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
result := (*ConsulGateway)(nil).Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
gateway := &ConsulGateway{
|
||||
Proxy: &ConsulGatewayProxy{
|
||||
ConnectTimeout: timeToPtr(3 * time.Second),
|
||||
EnvoyGatewayBindTaggedAddresses: true,
|
||||
EnvoyGatewayBindAddresses: map[string]*ConsulGatewayBindAddress{
|
||||
"listener1": {Address: "10.0.0.1", Port: 2000},
|
||||
"listener2": {Address: "10.0.0.1", Port: 2001},
|
||||
},
|
||||
EnvoyGatewayNoDefaultBind: true,
|
||||
EnvoyDNSDiscoveryType: "STRICT_DNS",
|
||||
Config: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"baz": 3,
|
||||
},
|
||||
},
|
||||
Ingress: &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 3333,
|
||||
Protocol: "tcp",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{
|
||||
"127.0.0.1", "127.0.0.1:3333",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
Terminating: &ConsulTerminatingConfigEntry{
|
||||
Services: []*ConsulLinkedService{{
|
||||
Name: "linked-service1",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
result := gateway.Copy()
|
||||
require.Equal(t, gateway, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulIngressConfigEntry_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulIngressConfigEntry)(nil)
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("empty fields", func(t *testing.T) {
|
||||
c := &ConsulIngressConfigEntry{
|
||||
TLS: nil,
|
||||
Listeners: []*ConsulIngressListener{},
|
||||
}
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c.TLS)
|
||||
require.Nil(t, c.Listeners)
|
||||
})
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
c := &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{Enabled: true},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 9090,
|
||||
Protocol: "http",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{"1.1.1.1"},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
c.Canonicalize()
|
||||
require.Equal(t, &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{Enabled: true},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 9090,
|
||||
Protocol: "http",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{"1.1.1.1"},
|
||||
}},
|
||||
}},
|
||||
}, c)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulIngressConfigEntry_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
result := (*ConsulIngressConfigEntry)(nil).Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
entry := &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 1111,
|
||||
Protocol: "http",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{"1.1.1.1", "1.1.1.1:9000"},
|
||||
}, {
|
||||
Name: "service2",
|
||||
Hosts: []string{"2.2.2.2"},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
result := entry.Copy()
|
||||
require.Equal(t, entry, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulTerminatingConfigEntry_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulTerminatingConfigEntry)(nil)
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("empty services", func(t *testing.T) {
|
||||
c := &ConsulTerminatingConfigEntry{
|
||||
Services: []*ConsulLinkedService{},
|
||||
}
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c.Services)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulTerminatingConfigEntry_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
result := (*ConsulIngressConfigEntry)(nil).Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
entry := &ConsulTerminatingConfigEntry{
|
||||
Services: []*ConsulLinkedService{{
|
||||
Name: "servic1",
|
||||
}, {
|
||||
Name: "service2",
|
||||
CAFile: "ca_file.pem",
|
||||
CertFile: "cert_file.pem",
|
||||
KeyFile: "key_file.pem",
|
||||
SNI: "sni.terminating.consul",
|
||||
}},
|
||||
}
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
result := entry.Copy()
|
||||
require.Equal(t, entry, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulMeshConfigEntry_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
ce := (*ConsulMeshConfigEntry)(nil)
|
||||
ce.Canonicalize()
|
||||
require.Nil(t, ce)
|
||||
})
|
||||
|
||||
t.Run("instantiated", func(t *testing.T) {
|
||||
ce := new(ConsulMeshConfigEntry)
|
||||
ce.Canonicalize()
|
||||
require.NotNil(t, ce)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulMeshConfigEntry_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
ce := (*ConsulMeshConfigEntry)(nil)
|
||||
ce2 := ce.Copy()
|
||||
require.Nil(t, ce2)
|
||||
})
|
||||
|
||||
t.Run("instantiated", func(t *testing.T) {
|
||||
ce := new(ConsulMeshConfigEntry)
|
||||
ce2 := ce.Copy()
|
||||
require.NotNil(t, ce2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulMeshGateway_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulMeshGateway)(nil)
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("unset mode", func(t *testing.T) {
|
||||
c := &ConsulMeshGateway{Mode: ""}
|
||||
c.Canonicalize()
|
||||
require.Equal(t, "", c.Mode)
|
||||
})
|
||||
|
||||
t.Run("set mode", func(t *testing.T) {
|
||||
c := &ConsulMeshGateway{Mode: "remote"}
|
||||
c.Canonicalize()
|
||||
require.Equal(t, "remote", c.Mode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConsulMeshGateway_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulMeshGateway)(nil)
|
||||
result := c.Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
t.Run("instantiated", func(t *testing.T) {
|
||||
c := &ConsulMeshGateway{
|
||||
Mode: "local",
|
||||
}
|
||||
result := c.Copy()
|
||||
require.Equal(t, c, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ServiceRegistrations is used to query the service endpoints.
|
||||
type ServiceRegistrations struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// ServiceRegistration is an instance of a single allocation advertising itself
|
||||
// as a named service with a specific address. Each registration is constructed
|
||||
// from the job specification Service block. Whether the service is registered
|
||||
// within Nomad, and therefore generates a ServiceRegistration is controlled by
|
||||
// the Service.Provider parameter.
|
||||
type ServiceRegistration struct {
|
||||
|
||||
// ID is the unique identifier for this registration. It currently follows
|
||||
// the Consul service registration format to provide consistency between
|
||||
// the two solutions.
|
||||
ID string
|
||||
|
||||
// ServiceName is the human friendly identifier for this service
|
||||
// registration.
|
||||
ServiceName string
|
||||
|
||||
// Namespace represents the namespace within which this service is
|
||||
// registered.
|
||||
Namespace string
|
||||
|
||||
// NodeID is Node.ID on which this service registration is currently
|
||||
// running.
|
||||
NodeID string
|
||||
|
||||
// Datacenter is the DC identifier of the node as identified by
|
||||
// Node.Datacenter.
|
||||
Datacenter string
|
||||
|
||||
// JobID is Job.ID and represents the job which contained the service block
|
||||
// which resulted in this service registration.
|
||||
JobID string
|
||||
|
||||
// AllocID is Allocation.ID and represents the allocation within which this
|
||||
// service is running.
|
||||
AllocID string
|
||||
|
||||
// Tags are determined from either Service.Tags or Service.CanaryTags and
|
||||
// help identify this service. Tags can also be used to perform lookups of
|
||||
// services depending on their state and role.
|
||||
Tags []string
|
||||
|
||||
// Address is the IP address of this service registration. This information
|
||||
// comes from the client and is not guaranteed to be routable; this depends
|
||||
// on cluster network topology.
|
||||
Address string
|
||||
|
||||
// Port is the port number on which this service registration is bound. It
|
||||
// is determined by a combination of factors on the client.
|
||||
Port int
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// ServiceRegistrationListStub represents all service registrations held within a
|
||||
// single namespace.
|
||||
type ServiceRegistrationListStub struct {
|
||||
|
||||
// Namespace details the namespace in which these services have been
|
||||
// registered.
|
||||
Namespace string
|
||||
|
||||
// Services is a list of services found within the namespace.
|
||||
Services []*ServiceRegistrationStub
|
||||
}
|
||||
|
||||
// ServiceRegistrationStub is the stub object describing an individual
|
||||
// namespaced service. The object is built in a manner which would allow us to
|
||||
// add additional fields in the future, if we wanted.
|
||||
type ServiceRegistrationStub struct {
|
||||
|
||||
// ServiceName is the human friendly name for this service as specified
|
||||
// within Service.Name.
|
||||
ServiceName string
|
||||
|
||||
// Tags is a list of unique tags found for this service. The list is
|
||||
// de-duplicated automatically by Nomad.
|
||||
Tags []string
|
||||
}
|
||||
|
||||
// ServiceRegistrations returns a new handle on the services endpoints.
|
||||
func (c *Client) ServiceRegistrations() *ServiceRegistrations {
|
||||
return &ServiceRegistrations{client: c}
|
||||
}
|
||||
|
||||
// List can be used to list all service registrations currently stored within
|
||||
// the target namespace. It returns a stub response object.
|
||||
func (s *ServiceRegistrations) List(q *QueryOptions) ([]*ServiceRegistrationListStub, *QueryMeta, error) {
|
||||
var resp []*ServiceRegistrationListStub
|
||||
qm, err := s.client.query("/v1/services", &resp, q)
|
||||
if err != nil {
|
||||
return nil, qm, err
|
||||
}
|
||||
return resp, qm, nil
|
||||
}
|
||||
|
||||
// Get is used to return a list of service registrations whose name matches the
|
||||
// specified parameter.
|
||||
func (s *ServiceRegistrations) Get(serviceName string, q *QueryOptions) ([]*ServiceRegistration, *QueryMeta, error) {
|
||||
var resp []*ServiceRegistration
|
||||
qm, err := s.client.query("/v1/service/"+url.PathEscape(serviceName), &resp, q)
|
||||
if err != nil {
|
||||
return nil, qm, err
|
||||
}
|
||||
return resp, qm, nil
|
||||
}
|
||||
|
||||
// Delete can be used to delete an individual service registration as defined
|
||||
// by its service name and service ID.
|
||||
func (s *ServiceRegistrations) Delete(serviceName, serviceID string, q *WriteOptions) (*WriteMeta, error) {
|
||||
path := fmt.Sprintf("/v1/service/%s/%s", url.PathEscape(serviceName), url.PathEscape(serviceID))
|
||||
wm, err := s.client.delete(path, nil, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wm, nil
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServiceRegistrations_List(t *testing.T) {
|
||||
// TODO(jrasell) add tests once registration process is in place.
|
||||
}
|
||||
|
||||
func TestServiceRegistrations_Get(t *testing.T) {
|
||||
// TODO(jrasell) add tests once registration process is in place.
|
||||
}
|
||||
|
||||
func TestServiceRegistrations_Delete(t *testing.T) {
|
||||
// TODO(jrasell) add tests once registration process is in place.
|
||||
}
|
||||
679
api/services.go
679
api/services.go
@@ -2,9 +2,134 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ServiceRegistration is an instance of a single allocation advertising itself
|
||||
// as a named service with a specific address. Each registration is constructed
|
||||
// from the job specification Service block. Whether the service is registered
|
||||
// within Nomad, and therefore generates a ServiceRegistration is controlled by
|
||||
// the Service.Provider parameter.
|
||||
type ServiceRegistration struct {
|
||||
|
||||
// ID is the unique identifier for this registration. It currently follows
|
||||
// the Consul service registration format to provide consistency between
|
||||
// the two solutions.
|
||||
ID string
|
||||
|
||||
// ServiceName is the human friendly identifier for this service
|
||||
// registration.
|
||||
ServiceName string
|
||||
|
||||
// Namespace represents the namespace within which this service is
|
||||
// registered.
|
||||
Namespace string
|
||||
|
||||
// NodeID is Node.ID on which this service registration is currently
|
||||
// running.
|
||||
NodeID string
|
||||
|
||||
// Datacenter is the DC identifier of the node as identified by
|
||||
// Node.Datacenter.
|
||||
Datacenter string
|
||||
|
||||
// JobID is Job.ID and represents the job which contained the service block
|
||||
// which resulted in this service registration.
|
||||
JobID string
|
||||
|
||||
// AllocID is Allocation.ID and represents the allocation within which this
|
||||
// service is running.
|
||||
AllocID string
|
||||
|
||||
// Tags are determined from either Service.Tags or Service.CanaryTags and
|
||||
// help identify this service. Tags can also be used to perform lookups of
|
||||
// services depending on their state and role.
|
||||
Tags []string
|
||||
|
||||
// Address is the IP address of this service registration. This information
|
||||
// comes from the client and is not guaranteed to be routable; this depends
|
||||
// on cluster network topology.
|
||||
Address string
|
||||
|
||||
// Port is the port number on which this service registration is bound. It
|
||||
// is determined by a combination of factors on the client.
|
||||
Port int
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// ServiceRegistrationListStub represents all service registrations held within a
|
||||
// single namespace.
|
||||
type ServiceRegistrationListStub struct {
|
||||
|
||||
// Namespace details the namespace in which these services have been
|
||||
// registered.
|
||||
Namespace string
|
||||
|
||||
// Services is a list of services found within the namespace.
|
||||
Services []*ServiceRegistrationStub
|
||||
}
|
||||
|
||||
// ServiceRegistrationStub is the stub object describing an individual
|
||||
// namespaced service. The object is built in a manner which would allow us to
|
||||
// add additional fields in the future, if we wanted.
|
||||
type ServiceRegistrationStub struct {
|
||||
|
||||
// ServiceName is the human friendly name for this service as specified
|
||||
// within Service.Name.
|
||||
ServiceName string
|
||||
|
||||
// Tags is a list of unique tags found for this service. The list is
|
||||
// de-duplicated automatically by Nomad.
|
||||
Tags []string
|
||||
}
|
||||
|
||||
|
||||
// Services is used to query the service endpoints.
|
||||
type Services struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Services returns a new handle on the services endpoints.
|
||||
func (c *Client) Services() *Services {
|
||||
return &Services{client: c}
|
||||
}
|
||||
|
||||
// List can be used to list all service registrations currently stored within
|
||||
// the target namespace. It returns a stub response object.
|
||||
func (s *Services) List(q *QueryOptions) ([]*ServiceRegistrationListStub, *QueryMeta, error) {
|
||||
var resp []*ServiceRegistrationListStub
|
||||
qm, err := s.client.query("/v1/services", &resp, q)
|
||||
if err != nil {
|
||||
return nil, qm, err
|
||||
}
|
||||
return resp, qm, nil
|
||||
}
|
||||
|
||||
// Get is used to return a list of service registrations whose name matches the
|
||||
// specified parameter.
|
||||
func (s *Services) Get(serviceName string, q *QueryOptions) ([]*ServiceRegistration, *QueryMeta, error) {
|
||||
var resp []*ServiceRegistration
|
||||
qm, err := s.client.query("/v1/service/"+url.PathEscape(serviceName), &resp, q)
|
||||
if err != nil {
|
||||
return nil, qm, err
|
||||
}
|
||||
return resp, qm, nil
|
||||
}
|
||||
|
||||
// Delete can be used to delete an individual service registration as defined
|
||||
// by its service name and service ID.
|
||||
func (s *Services) Delete(serviceName, serviceID string, q *WriteOptions) (*WriteMeta, error) {
|
||||
path := fmt.Sprintf("/v1/service/%s/%s", url.PathEscape(serviceName), url.PathEscape(serviceID))
|
||||
wm, err := s.client.delete(path, nil, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wm, nil
|
||||
}
|
||||
|
||||
// CheckRestart describes if and when a task should be restarted based on
|
||||
// failing health checks.
|
||||
type CheckRestart struct {
|
||||
@@ -181,557 +306,3 @@ func (s *Service) Canonicalize(t *Task, tg *TaskGroup, job *Job) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulConnect represents a Consul Connect jobspec stanza.
|
||||
type ConsulConnect struct {
|
||||
Native bool `hcl:"native,optional"`
|
||||
Gateway *ConsulGateway `hcl:"gateway,block"`
|
||||
SidecarService *ConsulSidecarService `mapstructure:"sidecar_service" hcl:"sidecar_service,block"`
|
||||
SidecarTask *SidecarTask `mapstructure:"sidecar_task" hcl:"sidecar_task,block"`
|
||||
}
|
||||
|
||||
func (cc *ConsulConnect) Canonicalize() {
|
||||
if cc == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cc.SidecarService.Canonicalize()
|
||||
cc.SidecarTask.Canonicalize()
|
||||
cc.Gateway.Canonicalize()
|
||||
}
|
||||
|
||||
// ConsulSidecarService represents a Consul Connect SidecarService jobspec
|
||||
// stanza.
|
||||
type ConsulSidecarService struct {
|
||||
Tags []string `hcl:"tags,optional"`
|
||||
Port string `hcl:"port,optional"`
|
||||
Proxy *ConsulProxy `hcl:"proxy,block"`
|
||||
DisableDefaultTCPCheck bool `mapstructure:"disable_default_tcp_check" hcl:"disable_default_tcp_check,optional"`
|
||||
}
|
||||
|
||||
func (css *ConsulSidecarService) Canonicalize() {
|
||||
if css == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(css.Tags) == 0 {
|
||||
css.Tags = nil
|
||||
}
|
||||
|
||||
css.Proxy.Canonicalize()
|
||||
}
|
||||
|
||||
// SidecarTask represents a subset of Task fields that can be set to override
|
||||
// the fields of the Task generated for the sidecar
|
||||
type SidecarTask struct {
|
||||
Name string `hcl:"name,optional"`
|
||||
Driver string `hcl:"driver,optional"`
|
||||
User string `hcl:"user,optional"`
|
||||
Config map[string]interface{} `hcl:"config,block"`
|
||||
Env map[string]string `hcl:"env,block"`
|
||||
Resources *Resources `hcl:"resources,block"`
|
||||
Meta map[string]string `hcl:"meta,block"`
|
||||
KillTimeout *time.Duration `mapstructure:"kill_timeout" hcl:"kill_timeout,optional"`
|
||||
LogConfig *LogConfig `mapstructure:"logs" hcl:"logs,block"`
|
||||
ShutdownDelay *time.Duration `mapstructure:"shutdown_delay" hcl:"shutdown_delay,optional"`
|
||||
KillSignal string `mapstructure:"kill_signal" hcl:"kill_signal,optional"`
|
||||
}
|
||||
|
||||
func (st *SidecarTask) Canonicalize() {
|
||||
if st == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(st.Config) == 0 {
|
||||
st.Config = nil
|
||||
}
|
||||
|
||||
if len(st.Env) == 0 {
|
||||
st.Env = nil
|
||||
}
|
||||
|
||||
if st.Resources == nil {
|
||||
st.Resources = DefaultResources()
|
||||
} else {
|
||||
st.Resources.Canonicalize()
|
||||
}
|
||||
|
||||
if st.LogConfig == nil {
|
||||
st.LogConfig = DefaultLogConfig()
|
||||
} else {
|
||||
st.LogConfig.Canonicalize()
|
||||
}
|
||||
|
||||
if len(st.Meta) == 0 {
|
||||
st.Meta = nil
|
||||
}
|
||||
|
||||
if st.KillTimeout == nil {
|
||||
st.KillTimeout = timeToPtr(5 * time.Second)
|
||||
}
|
||||
|
||||
if st.ShutdownDelay == nil {
|
||||
st.ShutdownDelay = timeToPtr(0)
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulProxy represents a Consul Connect sidecar proxy jobspec stanza.
|
||||
type ConsulProxy struct {
|
||||
LocalServiceAddress string `mapstructure:"local_service_address" hcl:"local_service_address,optional"`
|
||||
LocalServicePort int `mapstructure:"local_service_port" hcl:"local_service_port,optional"`
|
||||
ExposeConfig *ConsulExposeConfig `mapstructure:"expose" hcl:"expose,block"`
|
||||
Upstreams []*ConsulUpstream `hcl:"upstreams,block"`
|
||||
Config map[string]interface{} `hcl:"config,block"`
|
||||
}
|
||||
|
||||
func (cp *ConsulProxy) Canonicalize() {
|
||||
if cp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cp.ExposeConfig.Canonicalize()
|
||||
|
||||
if len(cp.Upstreams) == 0 {
|
||||
cp.Upstreams = nil
|
||||
}
|
||||
|
||||
for _, upstream := range cp.Upstreams {
|
||||
upstream.Canonicalize()
|
||||
}
|
||||
|
||||
if len(cp.Config) == 0 {
|
||||
cp.Config = nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulMeshGateway is used to configure mesh gateway usage when connecting to
|
||||
// a connect upstream in another datacenter.
|
||||
type ConsulMeshGateway struct {
|
||||
// Mode configures how an upstream should be accessed with regard to using
|
||||
// mesh gateways.
|
||||
//
|
||||
// local - the connect proxy makes outbound connections through mesh gateway
|
||||
// originating in the same datacenter.
|
||||
//
|
||||
// remote - the connect proxy makes outbound connections to a mesh gateway
|
||||
// in the destination datacenter.
|
||||
//
|
||||
// none (default) - no mesh gateway is used, the proxy makes outbound connections
|
||||
// directly to destination services.
|
||||
//
|
||||
// https://www.consul.io/docs/connect/gateways/mesh-gateway#modes-of-operation
|
||||
Mode string `mapstructure:"mode" hcl:"mode,optional"`
|
||||
}
|
||||
|
||||
func (c *ConsulMeshGateway) Canonicalize() {
|
||||
// Mode may be empty string, indicating behavior will defer to Consul
|
||||
// service-defaults config entry.
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ConsulMeshGateway) Copy() *ConsulMeshGateway {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulMeshGateway{
|
||||
Mode: c.Mode,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulUpstream represents a Consul Connect upstream jobspec stanza.
|
||||
type ConsulUpstream struct {
|
||||
DestinationName string `mapstructure:"destination_name" hcl:"destination_name,optional"`
|
||||
LocalBindPort int `mapstructure:"local_bind_port" hcl:"local_bind_port,optional"`
|
||||
Datacenter string `mapstructure:"datacenter" hcl:"datacenter,optional"`
|
||||
LocalBindAddress string `mapstructure:"local_bind_address" hcl:"local_bind_address,optional"`
|
||||
MeshGateway *ConsulMeshGateway `mapstructure:"mesh_gateway" hcl:"mesh_gateway,block"`
|
||||
}
|
||||
|
||||
func (cu *ConsulUpstream) Copy() *ConsulUpstream {
|
||||
if cu == nil {
|
||||
return nil
|
||||
}
|
||||
return &ConsulUpstream{
|
||||
DestinationName: cu.DestinationName,
|
||||
LocalBindPort: cu.LocalBindPort,
|
||||
Datacenter: cu.Datacenter,
|
||||
LocalBindAddress: cu.LocalBindAddress,
|
||||
MeshGateway: cu.MeshGateway.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
func (cu *ConsulUpstream) Canonicalize() {
|
||||
if cu == nil {
|
||||
return
|
||||
}
|
||||
cu.MeshGateway.Canonicalize()
|
||||
}
|
||||
|
||||
type ConsulExposeConfig struct {
|
||||
Path []*ConsulExposePath `mapstructure:"path" hcl:"path,block"`
|
||||
}
|
||||
|
||||
func (cec *ConsulExposeConfig) Canonicalize() {
|
||||
if cec == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(cec.Path) == 0 {
|
||||
cec.Path = nil
|
||||
}
|
||||
}
|
||||
|
||||
type ConsulExposePath struct {
|
||||
Path string `hcl:"path,optional"`
|
||||
Protocol string `hcl:"protocol,optional"`
|
||||
LocalPathPort int `mapstructure:"local_path_port" hcl:"local_path_port,optional"`
|
||||
ListenerPort string `mapstructure:"listener_port" hcl:"listener_port,optional"`
|
||||
}
|
||||
|
||||
// ConsulGateway is used to configure one of the Consul Connect Gateway types.
|
||||
type ConsulGateway struct {
|
||||
// Proxy is used to configure the Envoy instance acting as the gateway.
|
||||
Proxy *ConsulGatewayProxy `hcl:"proxy,block"`
|
||||
|
||||
// Ingress represents the Consul Configuration Entry for an Ingress Gateway.
|
||||
Ingress *ConsulIngressConfigEntry `hcl:"ingress,block"`
|
||||
|
||||
// Terminating represents the Consul Configuration Entry for a Terminating Gateway.
|
||||
Terminating *ConsulTerminatingConfigEntry `hcl:"terminating,block"`
|
||||
|
||||
// Mesh indicates the Consul service should be a Mesh Gateway.
|
||||
Mesh *ConsulMeshConfigEntry `hcl:"mesh,block"`
|
||||
}
|
||||
|
||||
func (g *ConsulGateway) Canonicalize() {
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
g.Proxy.Canonicalize()
|
||||
g.Ingress.Canonicalize()
|
||||
g.Terminating.Canonicalize()
|
||||
}
|
||||
|
||||
func (g *ConsulGateway) Copy() *ConsulGateway {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulGateway{
|
||||
Proxy: g.Proxy.Copy(),
|
||||
Ingress: g.Ingress.Copy(),
|
||||
Terminating: g.Terminating.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
type ConsulGatewayBindAddress struct {
|
||||
Name string `hcl:",label"`
|
||||
Address string `mapstructure:"address" hcl:"address,optional"`
|
||||
Port int `mapstructure:"port" hcl:"port,optional"`
|
||||
}
|
||||
|
||||
var (
|
||||
// defaultGatewayConnectTimeout is the default amount of time connections to
|
||||
// upstreams are allowed before timing out.
|
||||
defaultGatewayConnectTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// ConsulGatewayProxy is used to tune parameters of the proxy instance acting as
|
||||
// one of the forms of Connect gateways that Consul supports.
|
||||
//
|
||||
// https://www.consul.io/docs/connect/proxies/envoy#gateway-options
|
||||
type ConsulGatewayProxy struct {
|
||||
ConnectTimeout *time.Duration `mapstructure:"connect_timeout" hcl:"connect_timeout,optional"`
|
||||
EnvoyGatewayBindTaggedAddresses bool `mapstructure:"envoy_gateway_bind_tagged_addresses" hcl:"envoy_gateway_bind_tagged_addresses,optional"`
|
||||
EnvoyGatewayBindAddresses map[string]*ConsulGatewayBindAddress `mapstructure:"envoy_gateway_bind_addresses" hcl:"envoy_gateway_bind_addresses,block"`
|
||||
EnvoyGatewayNoDefaultBind bool `mapstructure:"envoy_gateway_no_default_bind" hcl:"envoy_gateway_no_default_bind,optional"`
|
||||
EnvoyDNSDiscoveryType string `mapstructure:"envoy_dns_discovery_type" hcl:"envoy_dns_discovery_type,optional"`
|
||||
Config map[string]interface{} `hcl:"config,block"` // escape hatch envoy config
|
||||
}
|
||||
|
||||
func (p *ConsulGatewayProxy) Canonicalize() {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if p.ConnectTimeout == nil {
|
||||
// same as the default from consul
|
||||
p.ConnectTimeout = timeToPtr(defaultGatewayConnectTimeout)
|
||||
}
|
||||
|
||||
if len(p.EnvoyGatewayBindAddresses) == 0 {
|
||||
p.EnvoyGatewayBindAddresses = nil
|
||||
}
|
||||
|
||||
if len(p.Config) == 0 {
|
||||
p.Config = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ConsulGatewayProxy) Copy() *ConsulGatewayProxy {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var binds map[string]*ConsulGatewayBindAddress = nil
|
||||
if p.EnvoyGatewayBindAddresses != nil {
|
||||
binds = make(map[string]*ConsulGatewayBindAddress, len(p.EnvoyGatewayBindAddresses))
|
||||
for k, v := range p.EnvoyGatewayBindAddresses {
|
||||
binds[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
var config map[string]interface{} = nil
|
||||
if p.Config != nil {
|
||||
config = make(map[string]interface{}, len(p.Config))
|
||||
for k, v := range p.Config {
|
||||
config[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulGatewayProxy{
|
||||
ConnectTimeout: timeToPtr(*p.ConnectTimeout),
|
||||
EnvoyGatewayBindTaggedAddresses: p.EnvoyGatewayBindTaggedAddresses,
|
||||
EnvoyGatewayBindAddresses: binds,
|
||||
EnvoyGatewayNoDefaultBind: p.EnvoyGatewayNoDefaultBind,
|
||||
EnvoyDNSDiscoveryType: p.EnvoyDNSDiscoveryType,
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulGatewayTLSConfig is used to configure TLS for a gateway.
|
||||
type ConsulGatewayTLSConfig struct {
|
||||
Enabled bool `hcl:"enabled,optional"`
|
||||
}
|
||||
|
||||
func (tc *ConsulGatewayTLSConfig) Canonicalize() {
|
||||
}
|
||||
|
||||
func (tc *ConsulGatewayTLSConfig) Copy() *ConsulGatewayTLSConfig {
|
||||
if tc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulGatewayTLSConfig{
|
||||
Enabled: tc.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulIngressService is used to configure a service fronted by the ingress gateway.
|
||||
type ConsulIngressService struct {
|
||||
// Namespace is not yet supported.
|
||||
// Namespace string
|
||||
Name string `hcl:"name,optional"`
|
||||
|
||||
Hosts []string `hcl:"hosts,optional"`
|
||||
}
|
||||
|
||||
func (s *ConsulIngressService) Canonicalize() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(s.Hosts) == 0 {
|
||||
s.Hosts = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConsulIngressService) Copy() *ConsulIngressService {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var hosts []string = nil
|
||||
if n := len(s.Hosts); n > 0 {
|
||||
hosts = make([]string, n)
|
||||
copy(hosts, s.Hosts)
|
||||
}
|
||||
|
||||
return &ConsulIngressService{
|
||||
Name: s.Name,
|
||||
Hosts: hosts,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
defaultIngressListenerProtocol = "tcp"
|
||||
)
|
||||
|
||||
// ConsulIngressListener is used to configure a listener on a Consul Ingress
|
||||
// Gateway.
|
||||
type ConsulIngressListener struct {
|
||||
Port int `hcl:"port,optional"`
|
||||
Protocol string `hcl:"protocol,optional"`
|
||||
Services []*ConsulIngressService `hcl:"service,block"`
|
||||
}
|
||||
|
||||
func (l *ConsulIngressListener) Canonicalize() {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if l.Protocol == "" {
|
||||
// same as default from consul
|
||||
l.Protocol = defaultIngressListenerProtocol
|
||||
}
|
||||
|
||||
if len(l.Services) == 0 {
|
||||
l.Services = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ConsulIngressListener) Copy() *ConsulIngressListener {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var services []*ConsulIngressService = nil
|
||||
if n := len(l.Services); n > 0 {
|
||||
services = make([]*ConsulIngressService, n)
|
||||
for i := 0; i < n; i++ {
|
||||
services[i] = l.Services[i].Copy()
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulIngressListener{
|
||||
Port: l.Port,
|
||||
Protocol: l.Protocol,
|
||||
Services: services,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulIngressConfigEntry represents the Consul Configuration Entry type for
|
||||
// an Ingress Gateway.
|
||||
//
|
||||
// https://www.consul.io/docs/agent/config-entries/ingress-gateway#available-fields
|
||||
type ConsulIngressConfigEntry struct {
|
||||
// Namespace is not yet supported.
|
||||
// Namespace string
|
||||
|
||||
TLS *ConsulGatewayTLSConfig `hcl:"tls,block"`
|
||||
Listeners []*ConsulIngressListener `hcl:"listener,block"`
|
||||
}
|
||||
|
||||
func (e *ConsulIngressConfigEntry) Canonicalize() {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
|
||||
e.TLS.Canonicalize()
|
||||
|
||||
if len(e.Listeners) == 0 {
|
||||
e.Listeners = nil
|
||||
}
|
||||
|
||||
for _, listener := range e.Listeners {
|
||||
listener.Canonicalize()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ConsulIngressConfigEntry) Copy() *ConsulIngressConfigEntry {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var listeners []*ConsulIngressListener = nil
|
||||
if n := len(e.Listeners); n > 0 {
|
||||
listeners = make([]*ConsulIngressListener, n)
|
||||
for i := 0; i < n; i++ {
|
||||
listeners[i] = e.Listeners[i].Copy()
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulIngressConfigEntry{
|
||||
TLS: e.TLS.Copy(),
|
||||
Listeners: listeners,
|
||||
}
|
||||
}
|
||||
|
||||
type ConsulLinkedService struct {
|
||||
Name string `hcl:"name,optional"`
|
||||
CAFile string `hcl:"ca_file,optional" mapstructure:"ca_file"`
|
||||
CertFile string `hcl:"cert_file,optional" mapstructure:"cert_file"`
|
||||
KeyFile string `hcl:"key_file,optional" mapstructure:"key_file"`
|
||||
SNI string `hcl:"sni,optional"`
|
||||
}
|
||||
|
||||
func (s *ConsulLinkedService) Canonicalize() {
|
||||
// nothing to do for now
|
||||
}
|
||||
|
||||
func (s *ConsulLinkedService) Copy() *ConsulLinkedService {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ConsulLinkedService{
|
||||
Name: s.Name,
|
||||
CAFile: s.CAFile,
|
||||
CertFile: s.CertFile,
|
||||
KeyFile: s.KeyFile,
|
||||
SNI: s.SNI,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulTerminatingConfigEntry represents the Consul Configuration Entry type
|
||||
// for a Terminating Gateway.
|
||||
//
|
||||
// https://www.consul.io/docs/agent/config-entries/terminating-gateway#available-fields
|
||||
type ConsulTerminatingConfigEntry struct {
|
||||
// Namespace is not yet supported.
|
||||
// Namespace string
|
||||
|
||||
Services []*ConsulLinkedService `hcl:"service,block"`
|
||||
}
|
||||
|
||||
func (e *ConsulTerminatingConfigEntry) Canonicalize() {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(e.Services) == 0 {
|
||||
e.Services = nil
|
||||
}
|
||||
|
||||
for _, service := range e.Services {
|
||||
service.Canonicalize()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ConsulTerminatingConfigEntry) Copy() *ConsulTerminatingConfigEntry {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var services []*ConsulLinkedService = nil
|
||||
if n := len(e.Services); n > 0 {
|
||||
services = make([]*ConsulLinkedService, n)
|
||||
for i := 0; i < n; i++ {
|
||||
services[i] = e.Services[i].Copy()
|
||||
}
|
||||
}
|
||||
|
||||
return &ConsulTerminatingConfigEntry{
|
||||
Services: services,
|
||||
}
|
||||
}
|
||||
|
||||
// ConsulMeshConfigEntry is a stub used to represent that the gateway service type
|
||||
// should be for a Mesh Gateway. Unlike Ingress and Terminating, there is no
|
||||
// actual Consul Config Entry type for mesh-gateway, at least for now. We still
|
||||
// create a type for future proofing, instead just using a bool for example.
|
||||
type ConsulMeshConfigEntry struct {
|
||||
// nothing in here
|
||||
}
|
||||
|
||||
func (e *ConsulMeshConfigEntry) Canonicalize() {
|
||||
return
|
||||
}
|
||||
|
||||
func (e *ConsulMeshConfigEntry) Copy() *ConsulMeshConfigEntry {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return new(ConsulMeshConfigEntry)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,19 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestServiceRegistrations_List(t *testing.T) {
|
||||
// TODO(jrasell) add tests once registration process is in place.
|
||||
}
|
||||
|
||||
func TestServiceRegistrations_Get(t *testing.T) {
|
||||
// TODO(jrasell) add tests once registration process is in place.
|
||||
}
|
||||
|
||||
func TestServiceRegistrations_Delete(t *testing.T) {
|
||||
// TODO(jrasell) add tests once registration process is in place.
|
||||
}
|
||||
|
||||
|
||||
func TestService_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
@@ -128,146 +141,6 @@ func TestService_CheckRestart(t *testing.T) {
|
||||
require.True(t, service.Checks[2].CheckRestart.IgnoreWarnings)
|
||||
}
|
||||
|
||||
func TestService_Connect_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil connect", func(t *testing.T) {
|
||||
cc := (*ConsulConnect)(nil)
|
||||
cc.Canonicalize()
|
||||
require.Nil(t, cc)
|
||||
})
|
||||
|
||||
t.Run("empty connect", func(t *testing.T) {
|
||||
cc := new(ConsulConnect)
|
||||
cc.Canonicalize()
|
||||
require.Empty(t, cc.Native)
|
||||
require.Nil(t, cc.SidecarService)
|
||||
require.Nil(t, cc.SidecarTask)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_Connect_ConsulSidecarService_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil sidecar_service", func(t *testing.T) {
|
||||
css := (*ConsulSidecarService)(nil)
|
||||
css.Canonicalize()
|
||||
require.Nil(t, css)
|
||||
})
|
||||
|
||||
t.Run("empty sidecar_service", func(t *testing.T) {
|
||||
css := new(ConsulSidecarService)
|
||||
css.Canonicalize()
|
||||
require.Empty(t, css.Tags)
|
||||
require.Nil(t, css.Proxy)
|
||||
})
|
||||
|
||||
t.Run("non-empty sidecar_service", func(t *testing.T) {
|
||||
css := &ConsulSidecarService{
|
||||
Tags: make([]string, 0),
|
||||
Port: "port",
|
||||
Proxy: &ConsulProxy{
|
||||
LocalServiceAddress: "lsa",
|
||||
LocalServicePort: 80,
|
||||
},
|
||||
}
|
||||
css.Canonicalize()
|
||||
require.Equal(t, &ConsulSidecarService{
|
||||
Tags: nil,
|
||||
Port: "port",
|
||||
Proxy: &ConsulProxy{
|
||||
LocalServiceAddress: "lsa",
|
||||
LocalServicePort: 80},
|
||||
}, css)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_Connect_ConsulProxy_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil proxy", func(t *testing.T) {
|
||||
cp := (*ConsulProxy)(nil)
|
||||
cp.Canonicalize()
|
||||
require.Nil(t, cp)
|
||||
})
|
||||
|
||||
t.Run("empty proxy", func(t *testing.T) {
|
||||
cp := new(ConsulProxy)
|
||||
cp.Canonicalize()
|
||||
require.Empty(t, cp.LocalServiceAddress)
|
||||
require.Zero(t, cp.LocalServicePort)
|
||||
require.Nil(t, cp.ExposeConfig)
|
||||
require.Nil(t, cp.Upstreams)
|
||||
require.Empty(t, cp.Config)
|
||||
})
|
||||
|
||||
t.Run("non empty proxy", func(t *testing.T) {
|
||||
cp := &ConsulProxy{
|
||||
LocalServiceAddress: "127.0.0.1",
|
||||
LocalServicePort: 80,
|
||||
ExposeConfig: new(ConsulExposeConfig),
|
||||
Upstreams: make([]*ConsulUpstream, 0),
|
||||
Config: make(map[string]interface{}),
|
||||
}
|
||||
cp.Canonicalize()
|
||||
require.Equal(t, "127.0.0.1", cp.LocalServiceAddress)
|
||||
require.Equal(t, 80, cp.LocalServicePort)
|
||||
require.Equal(t, &ConsulExposeConfig{}, cp.ExposeConfig)
|
||||
require.Nil(t, cp.Upstreams)
|
||||
require.Nil(t, cp.Config)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_Connect_ConsulUpstream_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil upstream", func(t *testing.T) {
|
||||
cu := (*ConsulUpstream)(nil)
|
||||
result := cu.Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
t.Run("complete upstream", func(t *testing.T) {
|
||||
cu := &ConsulUpstream{
|
||||
DestinationName: "dest1",
|
||||
Datacenter: "dc2",
|
||||
LocalBindPort: 2000,
|
||||
LocalBindAddress: "10.0.0.1",
|
||||
MeshGateway: &ConsulMeshGateway{Mode: "remote"},
|
||||
}
|
||||
result := cu.Copy()
|
||||
require.Equal(t, cu, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_Connect_ConsulUpstream_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil upstream", func(t *testing.T) {
|
||||
cu := (*ConsulUpstream)(nil)
|
||||
cu.Canonicalize()
|
||||
require.Nil(t, cu)
|
||||
})
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
cu := &ConsulUpstream{
|
||||
DestinationName: "dest1",
|
||||
Datacenter: "dc2",
|
||||
LocalBindPort: 2000,
|
||||
LocalBindAddress: "10.0.0.1",
|
||||
MeshGateway: &ConsulMeshGateway{Mode: ""},
|
||||
}
|
||||
cu.Canonicalize()
|
||||
require.Equal(t, &ConsulUpstream{
|
||||
DestinationName: "dest1",
|
||||
Datacenter: "dc2",
|
||||
LocalBindPort: 2000,
|
||||
LocalBindAddress: "10.0.0.1",
|
||||
MeshGateway: &ConsulMeshGateway{Mode: ""},
|
||||
}, cu)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_Connect_proxy_settings(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
@@ -319,316 +192,4 @@ func TestService_Tags(t *testing.T) {
|
||||
r.True(service.EnableTagOverride)
|
||||
r.Equal([]string{"a", "b"}, service.Tags)
|
||||
r.Equal([]string{"c", "d"}, service.CanaryTags)
|
||||
}
|
||||
|
||||
func TestService_Connect_SidecarTask_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil sidecar_task", func(t *testing.T) {
|
||||
st := (*SidecarTask)(nil)
|
||||
st.Canonicalize()
|
||||
require.Nil(t, st)
|
||||
})
|
||||
|
||||
t.Run("empty sidecar_task", func(t *testing.T) {
|
||||
st := new(SidecarTask)
|
||||
st.Canonicalize()
|
||||
require.Nil(t, st.Config)
|
||||
require.Nil(t, st.Env)
|
||||
require.Equal(t, DefaultResources(), st.Resources)
|
||||
require.Equal(t, DefaultLogConfig(), st.LogConfig)
|
||||
require.Nil(t, st.Meta)
|
||||
require.Equal(t, 5*time.Second, *st.KillTimeout)
|
||||
require.Equal(t, 0*time.Second, *st.ShutdownDelay)
|
||||
})
|
||||
|
||||
t.Run("non empty sidecar_task resources", func(t *testing.T) {
|
||||
exp := DefaultResources()
|
||||
exp.MemoryMB = intToPtr(333)
|
||||
st := &SidecarTask{
|
||||
Resources: &Resources{MemoryMB: intToPtr(333)},
|
||||
}
|
||||
st.Canonicalize()
|
||||
require.Equal(t, exp, st.Resources)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulGateway_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
cg := (*ConsulGateway)(nil)
|
||||
cg.Canonicalize()
|
||||
require.Nil(t, cg)
|
||||
})
|
||||
|
||||
t.Run("set defaults", func(t *testing.T) {
|
||||
cg := &ConsulGateway{
|
||||
Proxy: &ConsulGatewayProxy{
|
||||
ConnectTimeout: nil,
|
||||
EnvoyGatewayBindTaggedAddresses: true,
|
||||
EnvoyGatewayBindAddresses: make(map[string]*ConsulGatewayBindAddress, 0),
|
||||
EnvoyGatewayNoDefaultBind: true,
|
||||
Config: make(map[string]interface{}, 0),
|
||||
},
|
||||
Ingress: &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
Listeners: make([]*ConsulIngressListener, 0),
|
||||
},
|
||||
}
|
||||
cg.Canonicalize()
|
||||
require.Equal(t, timeToPtr(5*time.Second), cg.Proxy.ConnectTimeout)
|
||||
require.True(t, cg.Proxy.EnvoyGatewayBindTaggedAddresses)
|
||||
require.Nil(t, cg.Proxy.EnvoyGatewayBindAddresses)
|
||||
require.True(t, cg.Proxy.EnvoyGatewayNoDefaultBind)
|
||||
require.Empty(t, cg.Proxy.EnvoyDNSDiscoveryType)
|
||||
require.Nil(t, cg.Proxy.Config)
|
||||
require.Nil(t, cg.Ingress.Listeners)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulGateway_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
result := (*ConsulGateway)(nil).Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
gateway := &ConsulGateway{
|
||||
Proxy: &ConsulGatewayProxy{
|
||||
ConnectTimeout: timeToPtr(3 * time.Second),
|
||||
EnvoyGatewayBindTaggedAddresses: true,
|
||||
EnvoyGatewayBindAddresses: map[string]*ConsulGatewayBindAddress{
|
||||
"listener1": {Address: "10.0.0.1", Port: 2000},
|
||||
"listener2": {Address: "10.0.0.1", Port: 2001},
|
||||
},
|
||||
EnvoyGatewayNoDefaultBind: true,
|
||||
EnvoyDNSDiscoveryType: "STRICT_DNS",
|
||||
Config: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"baz": 3,
|
||||
},
|
||||
},
|
||||
Ingress: &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 3333,
|
||||
Protocol: "tcp",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{
|
||||
"127.0.0.1", "127.0.0.1:3333",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
Terminating: &ConsulTerminatingConfigEntry{
|
||||
Services: []*ConsulLinkedService{{
|
||||
Name: "linked-service1",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
result := gateway.Copy()
|
||||
require.Equal(t, gateway, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulIngressConfigEntry_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulIngressConfigEntry)(nil)
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("empty fields", func(t *testing.T) {
|
||||
c := &ConsulIngressConfigEntry{
|
||||
TLS: nil,
|
||||
Listeners: []*ConsulIngressListener{},
|
||||
}
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c.TLS)
|
||||
require.Nil(t, c.Listeners)
|
||||
})
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
c := &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{Enabled: true},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 9090,
|
||||
Protocol: "http",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{"1.1.1.1"},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
c.Canonicalize()
|
||||
require.Equal(t, &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{Enabled: true},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 9090,
|
||||
Protocol: "http",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{"1.1.1.1"},
|
||||
}},
|
||||
}},
|
||||
}, c)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulIngressConfigEntry_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
result := (*ConsulIngressConfigEntry)(nil).Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
entry := &ConsulIngressConfigEntry{
|
||||
TLS: &ConsulGatewayTLSConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
Listeners: []*ConsulIngressListener{{
|
||||
Port: 1111,
|
||||
Protocol: "http",
|
||||
Services: []*ConsulIngressService{{
|
||||
Name: "service1",
|
||||
Hosts: []string{"1.1.1.1", "1.1.1.1:9000"},
|
||||
}, {
|
||||
Name: "service2",
|
||||
Hosts: []string{"2.2.2.2"},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
result := entry.Copy()
|
||||
require.Equal(t, entry, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulTerminatingConfigEntry_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulTerminatingConfigEntry)(nil)
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("empty services", func(t *testing.T) {
|
||||
c := &ConsulTerminatingConfigEntry{
|
||||
Services: []*ConsulLinkedService{},
|
||||
}
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c.Services)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulTerminatingConfigEntry_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
result := (*ConsulIngressConfigEntry)(nil).Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
entry := &ConsulTerminatingConfigEntry{
|
||||
Services: []*ConsulLinkedService{{
|
||||
Name: "servic1",
|
||||
}, {
|
||||
Name: "service2",
|
||||
CAFile: "ca_file.pem",
|
||||
CertFile: "cert_file.pem",
|
||||
KeyFile: "key_file.pem",
|
||||
SNI: "sni.terminating.consul",
|
||||
}},
|
||||
}
|
||||
|
||||
t.Run("complete", func(t *testing.T) {
|
||||
result := entry.Copy()
|
||||
require.Equal(t, entry, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulMeshConfigEntry_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
ce := (*ConsulMeshConfigEntry)(nil)
|
||||
ce.Canonicalize()
|
||||
require.Nil(t, ce)
|
||||
})
|
||||
|
||||
t.Run("instantiated", func(t *testing.T) {
|
||||
ce := new(ConsulMeshConfigEntry)
|
||||
ce.Canonicalize()
|
||||
require.NotNil(t, ce)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulMeshConfigEntry_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
ce := (*ConsulMeshConfigEntry)(nil)
|
||||
ce2 := ce.Copy()
|
||||
require.Nil(t, ce2)
|
||||
})
|
||||
|
||||
t.Run("instantiated", func(t *testing.T) {
|
||||
ce := new(ConsulMeshConfigEntry)
|
||||
ce2 := ce.Copy()
|
||||
require.NotNil(t, ce2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulMeshGateway_Canonicalize(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulMeshGateway)(nil)
|
||||
c.Canonicalize()
|
||||
require.Nil(t, c)
|
||||
})
|
||||
|
||||
t.Run("unset mode", func(t *testing.T) {
|
||||
c := &ConsulMeshGateway{Mode: ""}
|
||||
c.Canonicalize()
|
||||
require.Equal(t, "", c.Mode)
|
||||
})
|
||||
|
||||
t.Run("set mode", func(t *testing.T) {
|
||||
c := &ConsulMeshGateway{Mode: "remote"}
|
||||
c.Canonicalize()
|
||||
require.Equal(t, "remote", c.Mode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ConsulMeshGateway_Copy(t *testing.T) {
|
||||
testutil.Parallel(t)
|
||||
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
c := (*ConsulMeshGateway)(nil)
|
||||
result := c.Copy()
|
||||
require.Nil(t, result)
|
||||
})
|
||||
|
||||
t.Run("instantiated", func(t *testing.T) {
|
||||
c := &ConsulMeshGateway{
|
||||
Mode: "local",
|
||||
}
|
||||
result := c.Copy()
|
||||
require.Equal(t, c, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func (s *ServiceDeleteCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
if _, err := client.ServiceRegistrations().Delete(args[0], args[1], nil); err != nil {
|
||||
if _, err := client.Services().Delete(args[0], args[1], nil); err != nil {
|
||||
s.Ui.Error(fmt.Sprintf("Error deleting service registration: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestServiceDeleteCommand_Run(t *testing.T) {
|
||||
require.Equal(t, 0, registerCode)
|
||||
|
||||
// Detail the service as we need the ID.
|
||||
serviceList, _, err := client.ServiceRegistrations().Get("service-discovery-nomad-delete", nil)
|
||||
serviceList, _, err := client.Services().Get("service-discovery-nomad-delete", nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, serviceList, 1)
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ func (s *ServiceInfoCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
serviceInfo, _, err := client.ServiceRegistrations().Get(args[0], nil)
|
||||
serviceInfo, _, err := client.Services().Get(args[0], nil)
|
||||
if err != nil {
|
||||
s.Ui.Error(fmt.Sprintf("Error listing service registrations: %s", err))
|
||||
return 1
|
||||
|
||||
@@ -89,7 +89,7 @@ func (s *ServiceListCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
list, _, err := client.ServiceRegistrations().List(nil)
|
||||
list, _, err := client.Services().List(nil)
|
||||
if err != nil {
|
||||
s.Ui.Error(fmt.Sprintf("Error listing service registrations: %s", err))
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user