config-entry: use custom MarshalJSON for mesh type

So that the Kind field is added to the JSON object.
This commit is contained in:
Daniel Nephin 2021-04-29 17:44:32 -04:00
parent bf4c289804
commit fcfd244269
4 changed files with 110 additions and 3 deletions

View File

@ -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) {

View File

@ -1,6 +1,7 @@
package structs package structs
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
@ -88,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)
}

View File

@ -1,7 +1,8 @@
package api package api
import "encoding/json"
type MeshConfigEntry struct { type MeshConfigEntry struct {
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"`
@ -36,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)
}

View File

@ -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