Merge pull request #10155 from hashicorp/dnephin/config-entry-remove-fields
config-entry: remove Kind and Name field from Mesh config entry
This commit is contained in:
commit
55f620d636
|
@ -4173,7 +4173,6 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
||||||
"bootstrap": [
|
"bootstrap": [
|
||||||
{
|
{
|
||||||
"kind": "mesh",
|
"kind": "mesh",
|
||||||
"name": "mesh",
|
|
||||||
"meta" : {
|
"meta" : {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim"
|
"gir": "zim"
|
||||||
|
@ -4190,7 +4189,6 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
||||||
config_entries {
|
config_entries {
|
||||||
bootstrap {
|
bootstrap {
|
||||||
kind = "mesh"
|
kind = "mesh"
|
||||||
name = "mesh"
|
|
||||||
meta {
|
meta {
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
"gir" = "zim"
|
"gir" = "zim"
|
||||||
|
@ -4206,8 +4204,6 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
||||||
rt.DataDir = dataDir
|
rt.DataDir = dataDir
|
||||||
rt.ConfigEntryBootstrap = []structs.ConfigEntry{
|
rt.ConfigEntryBootstrap = []structs.ConfigEntry{
|
||||||
&structs.MeshConfigEntry{
|
&structs.MeshConfigEntry{
|
||||||
Kind: structs.MeshConfig,
|
|
||||||
Name: structs.MeshConfigMesh,
|
|
||||||
Meta: map[string]string{
|
Meta: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim",
|
"gir": "zim",
|
||||||
|
@ -4228,7 +4224,6 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
||||||
"bootstrap": [
|
"bootstrap": [
|
||||||
{
|
{
|
||||||
"Kind": "mesh",
|
"Kind": "mesh",
|
||||||
"Name": "mesh",
|
|
||||||
"Meta" : {
|
"Meta" : {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim"
|
"gir": "zim"
|
||||||
|
@ -4245,7 +4240,6 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
||||||
config_entries {
|
config_entries {
|
||||||
bootstrap {
|
bootstrap {
|
||||||
Kind = "mesh"
|
Kind = "mesh"
|
||||||
Name = "mesh"
|
|
||||||
Meta {
|
Meta {
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
"gir" = "zim"
|
"gir" = "zim"
|
||||||
|
@ -4261,8 +4255,6 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
||||||
rt.DataDir = dataDir
|
rt.DataDir = dataDir
|
||||||
rt.ConfigEntryBootstrap = []structs.ConfigEntry{
|
rt.ConfigEntryBootstrap = []structs.ConfigEntry{
|
||||||
&structs.MeshConfigEntry{
|
&structs.MeshConfigEntry{
|
||||||
Kind: structs.MeshConfig,
|
|
||||||
Name: structs.MeshConfigMesh,
|
|
||||||
Meta: map[string]string{
|
Meta: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim",
|
"gir": "zim",
|
||||||
|
|
|
@ -7,10 +7,11 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
|
||||||
"github.com/hashicorp/consul/testrpc"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/hashicorp/consul/testrpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig_Get(t *testing.T) {
|
func TestConfig_Get(t *testing.T) {
|
||||||
|
@ -48,6 +49,18 @@ func TestConfig_Get(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Entry: &structs.MeshConfigEntry{
|
||||||
|
TransparentProxy: structs.TransparentProxyMeshConfig{
|
||||||
|
CatalogDestinationsOnly: true,
|
||||||
|
},
|
||||||
|
Meta: map[string]string{
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": "value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
out := false
|
out := false
|
||||||
|
@ -95,6 +108,37 @@ func TestConfig_Get(t *testing.T) {
|
||||||
_, err := a.srv.Config(resp, req)
|
_, err := a.srv.Config(resp, req)
|
||||||
require.Error(t, errors.New("Must provide either a kind or both kind and name"), err)
|
require.Error(t, errors.New("Must provide either a kind or both kind and name"), err)
|
||||||
})
|
})
|
||||||
|
t.Run("get the single mesh config", func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "/v1/config/mesh/mesh", nil)
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
obj, err := a.srv.Config(resp, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ce, ok := obj.(*structs.MeshConfigEntry)
|
||||||
|
require.True(t, ok, "wrong type %T", obj)
|
||||||
|
// Set indexes to expected values for assertions
|
||||||
|
ce.CreateIndex = 12
|
||||||
|
ce.ModifyIndex = 13
|
||||||
|
|
||||||
|
out, err := a.srv.marshalJSON(req, obj)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
{
|
||||||
|
"Kind": "mesh",
|
||||||
|
"TransparentProxy": {
|
||||||
|
"CatalogDestinationsOnly": true
|
||||||
|
},
|
||||||
|
"Meta":{
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": "value2"
|
||||||
|
},
|
||||||
|
"CreateIndex": 12,
|
||||||
|
"ModifyIndex": 13
|
||||||
|
}
|
||||||
|
`
|
||||||
|
require.JSONEq(t, expected, string(out))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfig_Delete(t *testing.T) {
|
func TestConfig_Delete(t *testing.T) {
|
||||||
|
|
|
@ -162,9 +162,11 @@ func (c *ConfigEntry) List(args *structs.ConfigEntryQuery, reply *structs.Indexe
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.Kind != "" && !structs.ValidateConfigEntryKind(args.Kind) {
|
if args.Kind != "" {
|
||||||
|
if _, err := structs.MakeConfigEntry(args.Kind, ""); err != nil {
|
||||||
return fmt.Errorf("invalid config entry kind: %s", args.Kind)
|
return fmt.Errorf("invalid config entry kind: %s", args.Kind)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return c.srv.blockingQuery(
|
return c.srv.blockingQuery(
|
||||||
&args.QueryOptions,
|
&args.QueryOptions,
|
||||||
|
|
|
@ -428,8 +428,6 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
||||||
|
|
||||||
// mesh config entry
|
// mesh config entry
|
||||||
meshConfig := &structs.MeshConfigEntry{
|
meshConfig := &structs.MeshConfigEntry{
|
||||||
Kind: structs.MeshConfig,
|
|
||||||
Name: structs.MeshConfigMesh,
|
|
||||||
TransparentProxy: structs.TransparentProxyMeshConfig{
|
TransparentProxy: structs.TransparentProxyMeshConfig{
|
||||||
CatalogDestinationsOnly: true,
|
CatalogDestinationsOnly: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1674,8 +1674,6 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
||||||
CorrelationID: meshConfigEntryID,
|
CorrelationID: meshConfigEntryID,
|
||||||
Result: &structs.ConfigEntryResponse{
|
Result: &structs.ConfigEntryResponse{
|
||||||
Entry: &structs.MeshConfigEntry{
|
Entry: &structs.MeshConfigEntry{
|
||||||
Kind: structs.MeshConfig,
|
|
||||||
Name: structs.MeshConfigMesh,
|
|
||||||
TransparentProxy: structs.TransparentProxyMeshConfig{},
|
TransparentProxy: structs.TransparentProxyMeshConfig{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -529,27 +529,12 @@ func MakeConfigEntry(kind, name string) (ConfigEntry, error) {
|
||||||
case ServiceIntentions:
|
case ServiceIntentions:
|
||||||
return &ServiceIntentionsConfigEntry{Name: name}, nil
|
return &ServiceIntentionsConfigEntry{Name: name}, nil
|
||||||
case MeshConfig:
|
case MeshConfig:
|
||||||
return &MeshConfigEntry{Name: name}, nil
|
return &MeshConfigEntry{}, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid config entry kind: %s", kind)
|
return nil, fmt.Errorf("invalid config entry kind: %s", kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateConfigEntryKind(kind string) bool {
|
|
||||||
switch kind {
|
|
||||||
case ServiceDefaults, ProxyDefaults:
|
|
||||||
return true
|
|
||||||
case ServiceRouter, ServiceSplitter, ServiceResolver:
|
|
||||||
return true
|
|
||||||
case IngressGateway, TerminatingGateway:
|
|
||||||
return true
|
|
||||||
case ServiceIntentions:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigEntryQuery is used when requesting info about a config entry.
|
// ConfigEntryQuery is used when requesting info about a config entry.
|
||||||
type ConfigEntryQuery struct {
|
type ConfigEntryQuery struct {
|
||||||
Kind string
|
Kind string
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/acl"
|
"github.com/hashicorp/consul/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MeshConfigEntry struct {
|
type MeshConfigEntry struct {
|
||||||
Kind string
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// TransparentProxy contains cluster-wide options pertaining to TPROXY mode
|
// TransparentProxy contains cluster-wide options pertaining to TPROXY mode
|
||||||
// when enabled.
|
// when enabled.
|
||||||
TransparentProxy TransparentProxyMeshConfig `alias:"transparent_proxy"`
|
TransparentProxy TransparentProxyMeshConfig `alias:"transparent_proxy"`
|
||||||
|
@ -36,7 +34,7 @@ func (e *MeshConfigEntry) GetName() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.Name
|
return MeshConfigMesh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MeshConfigEntry) GetMeta() map[string]string {
|
func (e *MeshConfigEntry) GetMeta() map[string]string {
|
||||||
|
@ -51,11 +49,7 @@ func (e *MeshConfigEntry) Normalize() error {
|
||||||
return fmt.Errorf("config entry is nil")
|
return fmt.Errorf("config entry is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Kind = MeshConfig
|
|
||||||
e.Name = MeshConfigMesh
|
|
||||||
|
|
||||||
e.EnterpriseMeta.Normalize()
|
e.EnterpriseMeta.Normalize()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,11 +57,6 @@ func (e *MeshConfigEntry) Validate() error {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return fmt.Errorf("config entry is nil")
|
return fmt.Errorf("config entry is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Name != MeshConfigMesh {
|
|
||||||
return fmt.Errorf("invalid name (%q), only %q is supported", e.Name, MeshConfigMesh)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateConfigEntryMeta(e.Meta); err != nil {
|
if err := validateConfigEntryMeta(e.Meta); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -100,3 +89,19 @@ func (e *MeshConfigEntry) GetEnterpriseMeta() *EnterpriseMeta {
|
||||||
|
|
||||||
return &e.EnterpriseMeta
|
return &e.EnterpriseMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON adds the Kind field so that the JSON can be decoded back into the
|
||||||
|
// correct type.
|
||||||
|
// This method is implemented on the structs type (as apposed to the api type)
|
||||||
|
// because that is what the API currently uses to return a response.
|
||||||
|
func (e *MeshConfigEntry) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias MeshConfigEntry
|
||||||
|
source := &struct {
|
||||||
|
Kind string
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Kind: MeshConfig,
|
||||||
|
Alias: (*Alias)(e),
|
||||||
|
}
|
||||||
|
return json.Marshal(source)
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ func validateUnusedKeys(unused []string) error {
|
||||||
for _, k := range unused {
|
for _, k := range unused {
|
||||||
switch {
|
switch {
|
||||||
case k == "CreateIndex" || k == "ModifyIndex":
|
case k == "CreateIndex" || k == "ModifyIndex":
|
||||||
|
case k == "kind" || k == "Kind":
|
||||||
|
// The kind field is used to determine the target, but doesn't need
|
||||||
|
// to exist on the target.
|
||||||
case strings.HasSuffix(strings.ToLower(k), "namespace"):
|
case strings.HasSuffix(strings.ToLower(k), "namespace"):
|
||||||
err = multierror.Append(err, fmt.Errorf("invalid config key %q, namespaces are a consul enterprise feature", k))
|
err = multierror.Append(err, fmt.Errorf("invalid config key %q, namespaces are a consul enterprise feature", k))
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1310,7 +1310,6 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
name: "mesh",
|
name: "mesh",
|
||||||
snake: `
|
snake: `
|
||||||
kind = "mesh"
|
kind = "mesh"
|
||||||
name = "mesh"
|
|
||||||
meta {
|
meta {
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
"gir" = "zim"
|
"gir" = "zim"
|
||||||
|
@ -1321,7 +1320,6 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
camel: `
|
camel: `
|
||||||
Kind = "mesh"
|
Kind = "mesh"
|
||||||
Name = "mesh"
|
|
||||||
Meta {
|
Meta {
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
"gir" = "zim"
|
"gir" = "zim"
|
||||||
|
@ -1331,8 +1329,6 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expect: &MeshConfigEntry{
|
expect: &MeshConfigEntry{
|
||||||
Kind: MeshConfig,
|
|
||||||
Name: MeshConfigMesh,
|
|
||||||
Meta: map[string]string{
|
Meta: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim",
|
"gir": "zim",
|
||||||
|
|
|
@ -550,8 +550,6 @@ func TestListenersFromSnapshot(t *testing.T) {
|
||||||
|
|
||||||
snap.ConnectProxy.MeshConfigSet = true
|
snap.ConnectProxy.MeshConfigSet = true
|
||||||
snap.ConnectProxy.MeshConfig = &structs.MeshConfigEntry{
|
snap.ConnectProxy.MeshConfig = &structs.MeshConfigEntry{
|
||||||
Kind: structs.MeshConfig,
|
|
||||||
Name: structs.MeshConfigMesh,
|
|
||||||
TransparentProxy: structs.TransparentProxyMeshConfig{
|
TransparentProxy: structs.TransparentProxyMeshConfig{
|
||||||
CatalogDestinationsOnly: true,
|
CatalogDestinationsOnly: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -295,7 +295,7 @@ func makeConfigEntry(kind, name string) (ConfigEntry, error) {
|
||||||
case ServiceIntentions:
|
case ServiceIntentions:
|
||||||
return &ServiceIntentionsConfigEntry{Kind: kind, Name: name}, nil
|
return &ServiceIntentionsConfigEntry{Kind: kind, Name: name}, nil
|
||||||
case MeshConfig:
|
case MeshConfig:
|
||||||
return &MeshConfigEntry{Kind: kind, Name: name}, nil
|
return &MeshConfigEntry{}, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid config entry kind: %s", kind)
|
return nil, fmt.Errorf("invalid config entry kind: %s", kind)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
type MeshConfigEntry struct {
|
type MeshConfigEntry struct {
|
||||||
Kind string
|
|
||||||
Name string
|
|
||||||
Namespace string `json:",omitempty"`
|
Namespace string `json:",omitempty"`
|
||||||
TransparentProxy TransparentProxyMeshConfig `alias:"transparent_proxy"`
|
TransparentProxy TransparentProxyMeshConfig `alias:"transparent_proxy"`
|
||||||
Meta map[string]string `json:",omitempty"`
|
Meta map[string]string `json:",omitempty"`
|
||||||
|
@ -15,11 +15,11 @@ type TransparentProxyMeshConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MeshConfigEntry) GetKind() string {
|
func (e *MeshConfigEntry) GetKind() string {
|
||||||
return e.Kind
|
return MeshConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MeshConfigEntry) GetName() string {
|
func (e *MeshConfigEntry) GetName() string {
|
||||||
return e.Name
|
return MeshConfigMesh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MeshConfigEntry) GetNamespace() string {
|
func (e *MeshConfigEntry) GetNamespace() string {
|
||||||
|
@ -37,3 +37,17 @@ func (e *MeshConfigEntry) GetCreateIndex() uint64 {
|
||||||
func (e *MeshConfigEntry) GetModifyIndex() uint64 {
|
func (e *MeshConfigEntry) GetModifyIndex() uint64 {
|
||||||
return e.ModifyIndex
|
return e.ModifyIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON adds the Kind field so that the JSON can be decoded back into the
|
||||||
|
// correct type.
|
||||||
|
func (e *MeshConfigEntry) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias MeshConfigEntry
|
||||||
|
source := &struct {
|
||||||
|
Kind string
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Kind: MeshConfig,
|
||||||
|
Alias: (*Alias)(e),
|
||||||
|
}
|
||||||
|
return json.Marshal(source)
|
||||||
|
}
|
||||||
|
|
|
@ -196,6 +196,64 @@ func TestAPI_ConfigEntries(t *testing.T) {
|
||||||
_, _, err = config_entries.Get(ServiceDefaults, "foo", nil)
|
_, _, err = config_entries.Get(ServiceDefaults, "foo", nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Mesh", func(t *testing.T) {
|
||||||
|
mesh := &MeshConfigEntry{
|
||||||
|
TransparentProxy: TransparentProxyMeshConfig{CatalogDestinationsOnly: true},
|
||||||
|
Meta: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"gir": "zim",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ce := c.ConfigEntries()
|
||||||
|
|
||||||
|
runStep(t, "set and get", func(t *testing.T) {
|
||||||
|
_, wm, err := ce.Set(mesh, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, wm)
|
||||||
|
require.NotEqual(t, 0, wm.RequestTime)
|
||||||
|
|
||||||
|
entry, qm, err := ce.Get(MeshConfig, MeshConfigMesh, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, qm)
|
||||||
|
require.NotEqual(t, 0, qm.RequestTime)
|
||||||
|
|
||||||
|
result, ok := entry.(*MeshConfigEntry)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
// ignore indexes
|
||||||
|
result.CreateIndex = 0
|
||||||
|
result.ModifyIndex = 0
|
||||||
|
require.Equal(t, mesh, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
runStep(t, "list", func(t *testing.T) {
|
||||||
|
entries, qm, err := ce.List(MeshConfig, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, qm)
|
||||||
|
require.NotEqual(t, 0, qm.RequestTime)
|
||||||
|
require.Len(t, entries, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
runStep(t, "delete", func(t *testing.T) {
|
||||||
|
wm, err := ce.Delete(MeshConfig, MeshConfigMesh, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, wm)
|
||||||
|
require.NotEqual(t, 0, wm.RequestTime)
|
||||||
|
|
||||||
|
// verify deletion
|
||||||
|
_, _, err = ce.Get(MeshConfig, MeshConfigMesh, nil)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func runStep(t *testing.T, name string, fn func(t *testing.T)) {
|
||||||
|
t.Helper()
|
||||||
|
if !t.Run(name, fn) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodeConfigEntry(t *testing.T) {
|
func TestDecodeConfigEntry(t *testing.T) {
|
||||||
|
@ -1141,7 +1199,6 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
body: `
|
body: `
|
||||||
{
|
{
|
||||||
"Kind": "mesh",
|
"Kind": "mesh",
|
||||||
"Name": "mesh",
|
|
||||||
"Meta" : {
|
"Meta" : {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim"
|
"gir": "zim"
|
||||||
|
@ -1152,8 +1209,6 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expect: &MeshConfigEntry{
|
expect: &MeshConfigEntry{
|
||||||
Kind: "mesh",
|
|
||||||
Name: "mesh",
|
|
||||||
Meta: map[string]string{
|
Meta: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim",
|
"gir": "zim",
|
||||||
|
|
|
@ -6,13 +6,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/command/flags"
|
"github.com/hashicorp/consul/command/flags"
|
||||||
"github.com/hashicorp/consul/command/helpers"
|
"github.com/hashicorp/consul/command/helpers"
|
||||||
"github.com/hashicorp/consul/lib/decode"
|
"github.com/hashicorp/consul/lib/decode"
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/mitchellh/cli"
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(ui cli.Ui) *cmd {
|
func New(ui cli.Ui) *cmd {
|
||||||
|
@ -155,6 +156,12 @@ func newDecodeConfigEntry(raw map[string]interface{}) (api.ConfigEntry, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range md.Unused {
|
for _, k := range md.Unused {
|
||||||
|
switch k {
|
||||||
|
case "kind", "Kind":
|
||||||
|
// The kind field is used to determine the target, but doesn't need
|
||||||
|
// to exist on the target.
|
||||||
|
continue
|
||||||
|
}
|
||||||
err = multierror.Append(err, fmt.Errorf("invalid config key %q", k))
|
err = multierror.Append(err, fmt.Errorf("invalid config key %q", k))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package write
|
package write
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -113,6 +114,36 @@ func TestConfigWrite(t *testing.T) {
|
||||||
require.NotEqual(t, 0, code)
|
require.NotEqual(t, 0, code)
|
||||||
require.NotEmpty(t, ui.ErrorWriter.String())
|
require.NotEmpty(t, ui.ErrorWriter.String())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("mesh config entry", func(t *testing.T) {
|
||||||
|
stdin := new(bytes.Buffer)
|
||||||
|
stdin.WriteString(`
|
||||||
|
kind = "mesh"
|
||||||
|
meta {
|
||||||
|
"foo" = "bar"
|
||||||
|
"gir" = "zim"
|
||||||
|
}
|
||||||
|
transparent_proxy {
|
||||||
|
catalog_destinations_only = true
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
ui := cli.NewMockUi()
|
||||||
|
c := New(ui)
|
||||||
|
c.testStdin = stdin
|
||||||
|
|
||||||
|
code := c.Run([]string{"-http-addr=" + a.HTTPAddr(), "-"})
|
||||||
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
require.Contains(t, ui.OutputWriter.String(),
|
||||||
|
`Config entry written: mesh/mesh`)
|
||||||
|
require.Equal(t, 0, code)
|
||||||
|
|
||||||
|
entry, _, err := client.ConfigEntries().Get(api.MeshConfig, api.MeshConfigMesh, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
proxy, ok := entry.(*api.MeshConfigEntry)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, map[string]string{"foo": "bar", "gir": "zim"}, proxy.Meta)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestParseConfigEntry is the 'api' mirror image of
|
// TestParseConfigEntry is the 'api' mirror image of
|
||||||
|
@ -2627,7 +2658,6 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
name: "mesh",
|
name: "mesh",
|
||||||
snake: `
|
snake: `
|
||||||
kind = "mesh"
|
kind = "mesh"
|
||||||
name = "mesh"
|
|
||||||
meta {
|
meta {
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
"gir" = "zim"
|
"gir" = "zim"
|
||||||
|
@ -2638,7 +2668,6 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
camel: `
|
camel: `
|
||||||
Kind = "mesh"
|
Kind = "mesh"
|
||||||
Name = "mesh"
|
|
||||||
Meta {
|
Meta {
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
"gir" = "zim"
|
"gir" = "zim"
|
||||||
|
@ -2650,7 +2679,6 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
snakeJSON: `
|
snakeJSON: `
|
||||||
{
|
{
|
||||||
"kind": "mesh",
|
"kind": "mesh",
|
||||||
"name": "mesh",
|
|
||||||
"meta" : {
|
"meta" : {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim"
|
"gir": "zim"
|
||||||
|
@ -2663,7 +2691,6 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
camelJSON: `
|
camelJSON: `
|
||||||
{
|
{
|
||||||
"Kind": "mesh",
|
"Kind": "mesh",
|
||||||
"Name": "mesh",
|
|
||||||
"Meta" : {
|
"Meta" : {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim"
|
"gir": "zim"
|
||||||
|
@ -2674,8 +2701,6 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expect: &api.MeshConfigEntry{
|
expect: &api.MeshConfigEntry{
|
||||||
Kind: api.MeshConfig,
|
|
||||||
Name: api.MeshConfigMesh,
|
|
||||||
Meta: map[string]string{
|
Meta: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim",
|
"gir": "zim",
|
||||||
|
|
Loading…
Reference in New Issue