mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 08:55:43 +03:00
As newer versions of Consul are released, the minimum version of Envoy it supports as a sidecar proxy also gets bumped. Starting with the upcoming Consul v1.9.X series, Envoy v1.11.X will no longer be supported. Current versions of Nomad hardcode a version of Envoy v1.11.2 to be used as the default implementation of Connect sidecar proxy. This PR introduces a change such that each Nomad Client will query its local Consul for a list of Envoy proxies that it supports (https://github.com/hashicorp/consul/pull/8545) and then launch the Connect sidecar proxy task using the latest supported version of Envoy. If the `SupportedProxies` API component is not available from Consul, Nomad will fallback to the old version of Envoy supported by old versions of Consul. Setting the meta configuration option `meta.connect.sidecar_image` or setting the `connect.sidecar_task` stanza will take precedence as is the current behavior for sidecar proxies. Setting the meta configuration option `meta.connect.gateway_image` will take precedence as is the current behavior for connect gateways. `meta.connect.sidecar_image` and `meta.connect.gateway_image` may make use of the special `${NOMAD_envoy_version}` variable interpolation, which resolves to the newest version of Envoy supported by the Consul agent. Addresses #8585 #7665
272 lines
7.8 KiB
Go
272 lines
7.8 KiB
Go
package consul
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var (
|
|
// the service as known by nomad
|
|
wanted = api.AgentServiceRegistration{
|
|
Kind: "",
|
|
ID: "aca4c175-1778-5ef4-0220-2ab434147d35",
|
|
Name: "myservice",
|
|
Tags: []string{"a", "b"},
|
|
Port: 9000,
|
|
Address: "1.1.1.1",
|
|
EnableTagOverride: true,
|
|
Meta: map[string]string{"foo": "1"},
|
|
Connect: &api.AgentServiceConnect{
|
|
Native: false,
|
|
SidecarService: &api.AgentServiceRegistration{
|
|
Kind: "connect-proxy",
|
|
ID: "_nomad-task-8e8413af-b5bb-aa67-2c24-c146c45f1ec9-group-mygroup-myservice-9001-sidecar-proxy",
|
|
Name: "name-sidecar-proxy",
|
|
Tags: []string{"x", "y", "z"},
|
|
},
|
|
},
|
|
}
|
|
|
|
// the service (and + connect proxy) as known by consul
|
|
existing = &api.AgentService{
|
|
Kind: "",
|
|
ID: "aca4c175-1778-5ef4-0220-2ab434147d35",
|
|
Service: "myservice",
|
|
Tags: []string{"a", "b"},
|
|
Port: 9000,
|
|
Address: "1.1.1.1",
|
|
EnableTagOverride: true,
|
|
Meta: map[string]string{"foo": "1"},
|
|
}
|
|
|
|
sidecar = &api.AgentService{
|
|
Kind: "connect-proxy",
|
|
ID: "_nomad-task-8e8413af-b5bb-aa67-2c24-c146c45f1ec9-group-mygroup-myservice-9001-sidecar-proxy",
|
|
Service: "myservice-sidecar-proxy",
|
|
Tags: []string{"x", "y", "z"},
|
|
}
|
|
)
|
|
|
|
func TestSyncLogic_agentServiceUpdateRequired(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// By default wanted and existing match. Each test should modify wanted in
|
|
// 1 way, and / or configure the type of sync operation that is being
|
|
// considered, then evaluate the result of the update-required algebra.
|
|
|
|
type asr = api.AgentServiceRegistration
|
|
type tweaker func(w asr) *asr // create a conveniently modifiable copy
|
|
|
|
try := func(
|
|
t *testing.T,
|
|
exp bool,
|
|
reason syncReason,
|
|
tweak tweaker) {
|
|
result := agentServiceUpdateRequired(reason, tweak(wanted), existing, sidecar)
|
|
require.Equal(t, exp, result)
|
|
}
|
|
|
|
t.Run("matching", func(t *testing.T) {
|
|
try(t, false, syncNewOps, func(w asr) *asr {
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different kind", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Kind = "other"
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different id", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.ID = "_other"
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different port", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Port = 9001
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different address", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Address = "2.2.2.2"
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different name", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Name = "bob"
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different enable_tag_override", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.EnableTagOverride = false
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different meta", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Meta = map[string]string{"foo": "2"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different tags syncNewOps eto=true", func(t *testing.T) {
|
|
// sync is required even though eto=true, because NewOps indicates the
|
|
// service definition in nomad has changed (e.g. job run a modified job)
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different tags syncPeriodic eto=true", func(t *testing.T) {
|
|
// sync is not required since eto=true and this is a periodic sync
|
|
// with consul - in which case we keep Consul's definition of the tags
|
|
try(t, false, syncPeriodic, func(w asr) *asr {
|
|
w.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different sidecar tags on syncPeriodic eto=true", func(t *testing.T) {
|
|
try(t, false, syncPeriodic, func(w asr) *asr {
|
|
// like the parent service, the sidecar's tags do not get enforced
|
|
// if ETO is true and this is a periodic sync
|
|
w.Connect.SidecarService.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different sidecar tags on syncNewOps eto=true", func(t *testing.T) {
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
// like the parent service, the sidecar's tags always get enforced
|
|
// regardless of ETO if this is a sync due to applied operations
|
|
w.Connect.SidecarService.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
// for remaining tests, EnableTagOverride = false
|
|
wanted.EnableTagOverride = false
|
|
existing.EnableTagOverride = false
|
|
|
|
t.Run("different tags syncPeriodic eto=false", func(t *testing.T) {
|
|
// sync is required because eto=false and the tags do not match
|
|
try(t, true, syncPeriodic, func(w asr) *asr {
|
|
w.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different tags syncNewOps eto=false", func(t *testing.T) {
|
|
// sync is required because eto=false and the tags do not match
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different sidecar tags on syncPeriodic eto=false", func(t *testing.T) {
|
|
// like the parent service, sync is required because eto=false and the
|
|
// sidecar's tags do not match
|
|
try(t, true, syncPeriodic, func(w asr) *asr {
|
|
w.Connect.SidecarService.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
|
|
t.Run("different sidecar tags syncNewOps eto=false", func(t *testing.T) {
|
|
// like the parent service, sync is required because eto=false and the
|
|
// sidecar's tags do not match
|
|
try(t, true, syncNewOps, func(w asr) *asr {
|
|
w.Connect.SidecarService.Tags = []string{"other", "tags"}
|
|
return &w
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestSyncLogic_maybeTweakTags(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
differentPointers := func(a, b []string) bool {
|
|
return &(a) != &(b)
|
|
}
|
|
|
|
try := func(inConsul, inConsulSC []string, eto bool) {
|
|
wanted := &api.AgentServiceRegistration{
|
|
Tags: []string{"original"},
|
|
Connect: &api.AgentServiceConnect{
|
|
SidecarService: &api.AgentServiceRegistration{
|
|
Tags: []string{"original-sidecar"},
|
|
},
|
|
},
|
|
EnableTagOverride: eto,
|
|
}
|
|
|
|
existing := &api.AgentService{Tags: inConsul}
|
|
sidecar := &api.AgentService{Tags: inConsulSC}
|
|
|
|
maybeTweakTags(wanted, existing, sidecar)
|
|
|
|
switch eto {
|
|
case false:
|
|
require.Equal(t, []string{"original"}, wanted.Tags)
|
|
require.Equal(t, []string{"original-sidecar"}, wanted.Connect.SidecarService.Tags)
|
|
require.True(t, differentPointers(wanted.Tags, wanted.Connect.SidecarService.Tags))
|
|
case true:
|
|
require.Equal(t, inConsul, wanted.Tags)
|
|
require.Equal(t, inConsulSC, wanted.Connect.SidecarService.Tags)
|
|
require.True(t, differentPointers(wanted.Tags, wanted.Connect.SidecarService.Tags))
|
|
}
|
|
}
|
|
|
|
try([]string{"original"}, []string{"original-sidecar"}, true)
|
|
try([]string{"original"}, []string{"original-sidecar"}, false)
|
|
try([]string{"modified"}, []string{"original-sidecar"}, true)
|
|
try([]string{"modified"}, []string{"original-sidecar"}, false)
|
|
try([]string{"original"}, []string{"modified-sidecar"}, true)
|
|
try([]string{"original"}, []string{"modified-sidecar"}, false)
|
|
try([]string{"modified"}, []string{"modified-sidecar"}, true)
|
|
try([]string{"modified"}, []string{"modified-sidecar"}, false)
|
|
}
|
|
|
|
func TestSyncLogic_maybeTweakTags_emptySC(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Check the edge cases where the connect service is deleted on the nomad
|
|
// side (i.e. are we checking multiple nil pointers).
|
|
|
|
try := func(asr *api.AgentServiceRegistration) {
|
|
maybeTweakTags(asr, existing, sidecar)
|
|
require.False(t, reflect.DeepEqual([]string{"original"}, asr.Tags))
|
|
}
|
|
|
|
try(&api.AgentServiceRegistration{
|
|
Tags: []string{"original"},
|
|
EnableTagOverride: true,
|
|
Connect: nil, // ooh danger!
|
|
})
|
|
|
|
try(&api.AgentServiceRegistration{
|
|
Tags: []string{"original"},
|
|
EnableTagOverride: true,
|
|
Connect: &api.AgentServiceConnect{
|
|
SidecarService: nil, // ooh danger!
|
|
},
|
|
})
|
|
}
|