mirror of https://github.com/hashicorp/consul
Backport of Fix issue with persisting proxy-defaults into release/1.17.x (#20488)
* backport of commitbackport/jm/no-parallel-dns-tests/tightly-liberal-emub5c6c1da83
* backport of commit1b7dbd7eea
--------- Co-authored-by: Derek Menteer <derek.menteer@hashicorp.com>
parent
0a56927902
commit
017ced4e8e
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
connect: Fix issue where re-persisting existing proxy-defaults using `http` protocol fails with a protocol-mismatch error.
|
||||||
|
```
|
|
@ -520,6 +520,58 @@ func TestConfig_Apply_ProxyDefaultsMeshGateway(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfig_Apply_ProxyDefaultsProtocol(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("too slow for testing.Short")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
a := NewTestAgent(t, "")
|
||||||
|
defer a.Shutdown()
|
||||||
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||||
|
|
||||||
|
writeConf := func(body string) {
|
||||||
|
req, _ := http.NewRequest("PUT", "/v1/config", bytes.NewBuffer([]byte(body)))
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
_, err := a.srv.ConfigApply(resp, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 200, resp.Code, "non-200 Response Code: %s", resp.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default protocol
|
||||||
|
writeConf(`{
|
||||||
|
"Kind": "proxy-defaults",
|
||||||
|
"Name": "global",
|
||||||
|
"Config": {
|
||||||
|
"Protocol": "http"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
// Create a router that depends on the protocol
|
||||||
|
writeConf(`{
|
||||||
|
"Kind": "service-router",
|
||||||
|
"Name": "route1"
|
||||||
|
}`)
|
||||||
|
|
||||||
|
// Ensure we can rewrite the proxy-defaults without a protocol-mismatch error.
|
||||||
|
// This should be taken care of in the ProxyConfigEntry.Normalize() function.
|
||||||
|
writeConf(`{
|
||||||
|
"Kind": "proxy-defaults",
|
||||||
|
"Name": "global",
|
||||||
|
"Config": {
|
||||||
|
"Protocol": "http",
|
||||||
|
"some-field": "is_changed"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
// Rewrite the router that depends on the protocol
|
||||||
|
writeConf(`{
|
||||||
|
"Kind": "service-router",
|
||||||
|
"Name": "route1"
|
||||||
|
}`)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfig_Apply_CAS(t *testing.T) {
|
func TestConfig_Apply_CAS(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
|
|
|
@ -6,7 +6,6 @@ package state
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
memdb "github.com/hashicorp/go-memdb"
|
memdb "github.com/hashicorp/go-memdb"
|
||||||
|
@ -528,7 +527,12 @@ func insertConfigEntryWithTxn(tx WriteTxn, idx uint64, conf structs.ConfigEntry)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case structs.ProxyDefaults:
|
case structs.ProxyDefaults:
|
||||||
err := addProtocol(conf.(*structs.ProxyConfigEntry))
|
proxyDefaults, ok := conf.(*structs.ProxyConfigEntry)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unable to cast config entry to proxy-defaults")
|
||||||
|
}
|
||||||
|
// Ensure we pre-compute the protocol before persisting always.
|
||||||
|
err := proxyDefaults.ComputeProtocol()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -557,21 +561,6 @@ func insertConfigEntryWithTxn(tx WriteTxn, idx uint64, conf structs.ConfigEntry)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxyConfig is a snippet from agent/xds/config.go:ProxyConfig
|
|
||||||
type proxyConfig struct {
|
|
||||||
Protocol string `mapstructure:"protocol"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func addProtocol(conf *structs.ProxyConfigEntry) error {
|
|
||||||
var cfg proxyConfig
|
|
||||||
err := mapstructure.WeakDecode(conf.Config, &cfg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
conf.Protocol = cfg.Protocol
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configEntryHasVirtualIP(c structs.ConfigEntry) bool {
|
func configEntryHasVirtualIP(c structs.ConfigEntry) bool {
|
||||||
if c == nil || c.GetName() == "" {
|
if c == nil || c.GetName() == "" {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -507,6 +507,22 @@ func (e *ProxyConfigEntry) GetMeta() map[string]string {
|
||||||
return e.Meta
|
return e.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ProxyConfigEntry) ComputeProtocol() error {
|
||||||
|
// proxyConfig is a snippet from agent/xds/config.go:ProxyConfig
|
||||||
|
// We calculate this up-front so that the expensive mapstructure decode
|
||||||
|
// is not needed during discovery chain compile time.
|
||||||
|
type proxyConfig struct {
|
||||||
|
Protocol string `mapstructure:"protocol"`
|
||||||
|
}
|
||||||
|
var cfg proxyConfig
|
||||||
|
err := mapstructure.WeakDecode(e.Config, &cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.Protocol = cfg.Protocol
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ProxyConfigEntry) Normalize() error {
|
func (e *ProxyConfigEntry) Normalize() error {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return fmt.Errorf("config entry is nil")
|
return fmt.Errorf("config entry is nil")
|
||||||
|
@ -524,6 +540,10 @@ func (e *ProxyConfigEntry) Normalize() error {
|
||||||
|
|
||||||
e.EnterpriseMeta.Normalize()
|
e.EnterpriseMeta.Normalize()
|
||||||
|
|
||||||
|
if err := e.ComputeProtocol(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
h, err := HashConfigEntry(e)
|
h, err := HashConfigEntry(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3662,6 +3662,47 @@ func TestProxyConfigEntry(t *testing.T) {
|
||||||
testConfigEntryNormalizeAndValidate(t, cases)
|
testConfigEntryNormalizeAndValidate(t, cases)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProxyConfigEntry_ComputeProtocol(t *testing.T) {
|
||||||
|
t.Run("ComputeProtocol sets protocol field correctly", func(t *testing.T) {
|
||||||
|
pd := &ProxyConfigEntry{
|
||||||
|
Kind: ProxyDefaults,
|
||||||
|
Name: "global",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"protocol": "http",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.NoError(t, pd.ComputeProtocol())
|
||||||
|
require.Equal(t, &ProxyConfigEntry{
|
||||||
|
Kind: ProxyDefaults,
|
||||||
|
Name: "global",
|
||||||
|
Protocol: "http",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"protocol": "http",
|
||||||
|
},
|
||||||
|
}, pd)
|
||||||
|
})
|
||||||
|
t.Run("Normalize sets protocol field correctly", func(t *testing.T) {
|
||||||
|
pd := &ProxyConfigEntry{
|
||||||
|
Kind: ProxyDefaults,
|
||||||
|
Name: "global",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"protocol": "http",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.NoError(t, pd.Normalize())
|
||||||
|
pd.Hash = 0
|
||||||
|
require.Equal(t, &ProxyConfigEntry{
|
||||||
|
Kind: ProxyDefaults,
|
||||||
|
Name: "global",
|
||||||
|
Protocol: "http",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"protocol": "http",
|
||||||
|
},
|
||||||
|
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
|
||||||
|
}, pd)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func requireContainsLower(t *testing.T, haystack, needle string) {
|
func requireContainsLower(t *testing.T, haystack, needle string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
require.Contains(t, strings.ToLower(haystack), strings.ToLower(needle))
|
require.Contains(t, strings.ToLower(haystack), strings.ToLower(needle))
|
||||||
|
|
Loading…
Reference in New Issue