consul/command/config/write/config_write_test.go

3102 lines
60 KiB
Go
Raw Normal View History

Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
package write
import (
"bytes"
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
"io"
"strings"
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
"testing"
"time"
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
"github.com/hashicorp/consul/agent/structs"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/require"
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
"github.com/hashicorp/consul/agent"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/testutil"
)
func TestConfigWrite_noTabs(t *testing.T) {
t.Parallel()
require.NotContains(t, New(cli.NewMockUi()).Help(), "\t")
}
func TestConfigWrite(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
t.Parallel()
a := agent.NewTestAgent(t, ``)
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
defer a.Shutdown()
client := a.Client()
t.Run("File", func(t *testing.T) {
ui := cli.NewMockUi()
c := New(ui)
f := testutil.TempFile(t, "config-write-svc-web.hcl")
_, err := f.WriteString(`
Kind = "service-defaults"
Name = "web"
Protocol = "udp"
`)
require.NoError(t, err)
args := []string{
"-http-addr=" + a.HTTPAddr(),
f.Name(),
}
code := c.Run(args)
require.Empty(t, ui.ErrorWriter.String())
require.Contains(t, ui.OutputWriter.String(),
`Config entry written: service-defaults/web`)
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
require.Equal(t, 0, code)
entry, _, err := client.ConfigEntries().Get("service-defaults", "web", nil)
require.NoError(t, err)
svc, ok := entry.(*api.ServiceConfigEntry)
require.True(t, ok)
require.Equal(t, api.ServiceDefaults, svc.Kind)
require.Equal(t, "web", svc.Name)
require.Equal(t, "udp", svc.Protocol)
})
t.Run("Stdin", func(t *testing.T) {
stdinR, stdinW := io.Pipe()
ui := cli.NewMockUi()
c := New(ui)
c.testStdin = stdinR
go func() {
stdinW.Write([]byte(`{
"Kind": "proxy-defaults",
"Name": "global",
"Config": {
"foo": "bar",
"bar": 1.0
}
}`))
stdinW.Close()
}()
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-",
}
code := c.Run(args)
require.Empty(t, ui.ErrorWriter.String())
require.Contains(t, ui.OutputWriter.String(),
`Config entry written: proxy-defaults/global`)
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
require.Equal(t, 0, code)
entry, _, err := client.ConfigEntries().Get(api.ProxyDefaults, api.ProxyConfigGlobal, nil)
require.NoError(t, err)
proxy, ok := entry.(*api.ProxyConfigEntry)
require.True(t, ok)
require.Equal(t, api.ProxyDefaults, proxy.Kind)
require.Equal(t, api.ProxyConfigGlobal, proxy.Name)
require.Equal(t, map[string]interface{}{"foo": "bar", "bar": 1.0}, proxy.Config)
})
t.Run("No config", func(t *testing.T) {
ui := cli.NewMockUi()
c := New(ui)
code := c.Run([]string{})
require.NotEqual(t, 0, code)
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 {
mesh_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
// agent/structs/config_entry_test.go:TestDecodeConfigEntry
func TestParseConfigEntry(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
camel, camelJSON string
snake, snakeJSON string
expect api.ConfigEntry
expectJSON api.ConfigEntry
expectErr string
}{
{
name: "proxy-defaults: extra fields or typo",
snake: `
kind = "proxy-defaults"
name = "main"
cornfig {
"foo" = 19
}
`,
camel: `
Kind = "proxy-defaults"
Name = "main"
Cornfig {
"foo" = 19
}
`,
snakeJSON: `
{
"kind": "proxy-defaults",
"name": "main",
"cornfig": {
"foo": 19
}
}
`,
camelJSON: `
{
"Kind": "proxy-defaults",
"Name": "main",
"Cornfig": {
"foo": 19
}
}
`,
expectErr: `invalid config key "cornfig"`,
},
{
name: "proxy-defaults",
snake: `
kind = "proxy-defaults"
name = "main"
meta {
"foo" = "bar"
"gir" = "zim"
}
config {
"foo" = 19
"bar" = "abc"
"moreconfig" {
"moar" = "config"
}
}
mesh_gateway {
mode = "remote"
}
mode = "direct"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
`,
camel: `
Kind = "proxy-defaults"
Name = "main"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Config {
"foo" = 19
"bar" = "abc"
"moreconfig" {
"moar" = "config"
}
}
MeshGateway {
Mode = "remote"
}
Mode = "direct"
TransparentProxy = {
outbound_listener_port = 10101
dialed_directly = true
}
`,
snakeJSON: `
{
"kind": "proxy-defaults",
"name": "main",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"config": {
"foo": 19,
"bar": "abc",
"moreconfig": {
"moar": "config"
}
},
"mesh_gateway": {
"mode": "remote"
},
"mode": "direct",
"transparent_proxy": {
"outbound_listener_port": 10101,
"dialed_directly": true
}
}
`,
camelJSON: `
{
"Kind": "proxy-defaults",
"Name": "main",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"Config": {
"foo": 19,
"bar": "abc",
"moreconfig": {
"moar": "config"
}
},
"MeshGateway": {
"Mode": "remote"
},
"Mode": "direct",
"TransparentProxy": {
"OutboundListenerPort": 10101,
"DialedDirectly": true
}
}
`,
expect: &api.ProxyConfigEntry{
Kind: "proxy-defaults",
Name: "main",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Config: map[string]interface{}{
"foo": 19,
"bar": "abc",
"moreconfig": map[string]interface{}{
"moar": "config",
},
},
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeRemote,
},
Mode: api.ProxyModeDirect,
TransparentProxy: &api.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
expectJSON: &api.ProxyConfigEntry{
Kind: "proxy-defaults",
Name: "main",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Config: map[string]interface{}{
"foo": float64(19), // json decoding gives float64 instead of int here
"bar": "abc",
"moreconfig": map[string]interface{}{
"moar": "config",
},
},
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeRemote,
},
Mode: api.ProxyModeDirect,
TransparentProxy: &api.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
},
{
name: "terminating-gateway",
snake: `
kind = "terminating-gateway"
name = "terminating-gw-west"
namespace = "default"
meta {
"foo" = "bar"
"gir" = "zim"
}
services = [
{
name = "billing"
namespace = "biz"
ca_file = "/etc/ca.crt"
cert_file = "/etc/client.crt"
key_file = "/etc/tls.key"
sni = "mydomain"
},
{
name = "*"
namespace = "ops"
}
]
`,
camel: `
Kind = "terminating-gateway"
Name = "terminating-gw-west"
Namespace = "default"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Services = [
{
Name = "billing"
Namespace = "biz"
CAFile = "/etc/ca.crt"
CertFile = "/etc/client.crt"
KeyFile = "/etc/tls.key"
SNI = "mydomain"
},
{
Name = "*"
Namespace = "ops"
}
]
`,
snakeJSON: `
{
"kind": "terminating-gateway",
"name": "terminating-gw-west",
"namespace": "default",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"services": [
{
"name": "billing",
"namespace": "biz",
"ca_file": "/etc/ca.crt",
"cert_file": "/etc/client.crt",
"key_file": "/etc/tls.key",
"sni": "mydomain"
},
{
"name": "*",
"namespace": "ops"
}
]
}
`,
camelJSON: `
{
"Kind": "terminating-gateway",
"Name": "terminating-gw-west",
"Namespace": "default",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"Services": [
{
"Name": "billing",
"Namespace": "biz",
"CAFile": "/etc/ca.crt",
"CertFile": "/etc/client.crt",
"KeyFile": "/etc/tls.key",
"SNI": "mydomain"
},
{
"Name": "*",
"Namespace": "ops"
}
]
}
`,
expect: &api.TerminatingGatewayConfigEntry{
Kind: "terminating-gateway",
Name: "terminating-gw-west",
Namespace: "default",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Services: []api.LinkedService{
{
Name: "billing",
Namespace: "biz",
CAFile: "/etc/ca.crt",
CertFile: "/etc/client.crt",
KeyFile: "/etc/tls.key",
SNI: "mydomain",
},
{
Name: "*",
Namespace: "ops",
},
},
},
expectJSON: &api.TerminatingGatewayConfigEntry{
Kind: "terminating-gateway",
Name: "terminating-gw-west",
Namespace: "default",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Services: []api.LinkedService{
{
Name: "billing",
Namespace: "biz",
CAFile: "/etc/ca.crt",
CertFile: "/etc/client.crt",
KeyFile: "/etc/tls.key",
SNI: "mydomain",
},
{
Name: "*",
Namespace: "ops",
},
},
},
},
{
name: "service-defaults: kitchen sink",
snake: `
kind = "service-defaults"
name = "main"
meta {
"foo" = "bar"
"gir" = "zim"
}
protocol = "http"
external_sni = "abc-123"
mesh_gateway {
mode = "remote"
}
mode = "direct"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
upstream_config {
overrides = [
{
name = "redis"
passive_health_check {
max_failures = 3
interval = "2s"
}
envoy_listener_json = "{ \"listener-foo\": 5 }"
envoy_cluster_json = "{ \"cluster-bar\": 5 }"
protocol = "grpc"
connect_timeout_ms = 6543
},
{
name = "finance--billing"
mesh_gateway {
mode = "remote"
}
limits {
max_connections = 1111
max_pending_requests = 2222
max_concurrent_requests = 3333
}
}
]
defaults {
envoy_cluster_json = "zip"
envoy_listener_json = "zop"
connect_timeout_ms = 5000
protocol = "http"
limits {
max_connections = 3
max_pending_requests = 4
max_concurrent_requests = 5
}
passive_health_check {
max_failures = 5
interval = "4s"
}
}
}
`,
camel: `
Kind = "service-defaults"
Name = "main"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Protocol = "http"
ExternalSNI = "abc-123"
MeshGateway {
Mode = "remote"
}
Mode = "direct"
TransparentProxy = {
outbound_listener_port = 10101
dialed_directly = true
}
UpstreamConfig {
Overrides = [
{
Name = "redis"
PassiveHealthCheck {
MaxFailures = 3
Interval = "2s"
}
EnvoyListenerJson = "{ \"listener-foo\": 5 }"
EnvoyClusterJson = "{ \"cluster-bar\": 5 }"
Protocol = "grpc"
ConnectTimeoutMs = 6543
},
{
Name = "finance--billing"
MeshGateway {
Mode = "remote"
}
Limits {
MaxConnections = 1111
MaxPendingRequests = 2222
MaxConcurrentRequests = 3333
}
}
]
Defaults {
EnvoyClusterJson = "zip"
EnvoyListenerJson = "zop"
ConnectTimeoutMs = 5000
Protocol = "http"
Limits {
MaxConnections = 3
MaxPendingRequests = 4
MaxConcurrentRequests = 5
}
PassiveHealthCheck {
MaxFailures = 5
Interval = "4s"
}
}
}
`,
snakeJSON: `
{
"kind": "service-defaults",
"name": "main",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"protocol": "http",
"external_sni": "abc-123",
"mesh_gateway": {
"mode": "remote"
},
"mode": "direct",
"transparent_proxy": {
"outbound_listener_port": 10101,
"dialed_directly": true
},
"upstream_config": {
"overrides": [
{
"name": "redis",
"passive_health_check": {
"max_failures": 3,
"interval": "2s"
},
"envoy_listener_json": "{ \"listener-foo\": 5 }",
"envoy_cluster_json": "{ \"cluster-bar\": 5 }",
"protocol": "grpc",
"connect_timeout_ms": 6543
},
{
"name": "finance--billing",
"mesh_gateway": {
"mode": "remote"
},
"limits": {
"max_connections": 1111,
"max_pending_requests": 2222,
"max_concurrent_requests": 3333
}
}
],
"defaults": {
"envoy_cluster_json": "zip",
"envoy_listener_json": "zop",
"connect_timeout_ms": 5000,
"protocol": "http",
"limits": {
"max_connections": 3,
"max_pending_requests": 4,
"max_concurrent_requests": 5
},
"passive_health_check": {
"max_failures": 5,
"interval": "4s"
}
}
}
}
`,
camelJSON: `
{
"Kind": "service-defaults",
"Name": "main",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"Protocol": "http",
"ExternalSNI": "abc-123",
"MeshGateway": {
"Mode": "remote"
},
"Mode": "direct",
"TransparentProxy": {
"OutboundListenerPort": 10101,
"DialedDirectly": true
},
"UpstreamConfig": {
"Overrides": [
{
"Name": "redis",
"PassiveHealthCheck": {
"MaxFailures": 3,
"Interval": "2s"
},
"EnvoyListenerJson": "{ \"listener-foo\": 5 }",
"EnvoyClusterJson": "{ \"cluster-bar\": 5 }",
"Protocol": "grpc",
"ConnectTimeoutMs": 6543
},
{
"Name": "finance--billing",
"MeshGateway": {
"Mode": "remote"
},
"Limits": {
"MaxConnections": 1111,
"MaxPendingRequests": 2222,
"MaxConcurrentRequests": 3333
}
}
],
"Defaults": {
"EnvoyClusterJson": "zip",
"EnvoyListenerJson": "zop",
"ConnectTimeoutMs": 5000,
"Protocol": "http",
"Limits": {
"MaxConnections": 3,
"MaxPendingRequests": 4,
"MaxConcurrentRequests": 5
},
"PassiveHealthCheck": {
"MaxFailures": 5,
"Interval": "4s"
}
}
}
}
`,
expect: &api.ServiceConfigEntry{
Kind: "service-defaults",
Name: "main",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Protocol: "http",
ExternalSNI: "abc-123",
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeRemote,
},
Mode: api.ProxyModeDirect,
TransparentProxy: &api.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
UpstreamConfig: &api.UpstreamConfiguration{
Overrides: []*api.UpstreamConfig{
{
Name: "redis",
PassiveHealthCheck: &api.PassiveHealthCheck{
MaxFailures: 3,
Interval: 2 * time.Second,
},
EnvoyListenerJSON: `{ "listener-foo": 5 }`,
EnvoyClusterJSON: `{ "cluster-bar": 5 }`,
Protocol: "grpc",
ConnectTimeoutMs: 6543,
},
{
Name: "finance--billing",
MeshGateway: api.MeshGatewayConfig{
Mode: "remote",
},
Limits: &api.UpstreamLimits{
MaxConnections: intPointer(1111),
MaxPendingRequests: intPointer(2222),
MaxConcurrentRequests: intPointer(3333),
},
},
},
Defaults: &api.UpstreamConfig{
EnvoyClusterJSON: "zip",
EnvoyListenerJSON: "zop",
Protocol: "http",
ConnectTimeoutMs: 5000,
Limits: &api.UpstreamLimits{
MaxConnections: intPointer(3),
MaxPendingRequests: intPointer(4),
MaxConcurrentRequests: intPointer(5),
},
PassiveHealthCheck: &api.PassiveHealthCheck{
MaxFailures: 5,
Interval: 4 * time.Second,
},
},
},
},
},
{
name: "service-router: kitchen sink",
snake: `
kind = "service-router"
name = "main"
2021-12-06 18:58:33 +00:00
partition = "pepper"
meta {
"foo" = "bar"
"gir" = "zim"
}
routes = [
{
match {
http {
path_exact = "/foo"
header = [
{
name = "debug1"
present = true
},
{
name = "debug2"
present = false
invert = true
},
{
name = "debug3"
exact = "1"
},
{
name = "debug4"
prefix = "aaa"
},
{
name = "debug5"
suffix = "bbb"
},
{
name = "debug6"
regex = "a.*z"
},
]
}
}
destination {
2021-12-06 18:58:33 +00:00
service = "carrot"
service_subset = "kale"
namespace = "leek"
partition = "chard"
prefix_rewrite = "/alternate"
request_timeout = "99s"
num_retries = 12345
retry_on_connect_failure = true
retry_on_status_codes = [401, 209]
}
},
{
match {
http {
path_prefix = "/foo"
methods = [ "GET", "DELETE" ]
query_param = [
{
name = "hack1"
present = true
},
{
name = "hack2"
exact = "1"
},
{
name = "hack3"
regex = "a.*z"
},
]
}
}
},
{
match {
http {
path_regex = "/foo"
}
}
},
]
`,
camel: `
Kind = "service-router"
Name = "main"
2021-12-06 18:58:33 +00:00
Partition = "pepper"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Routes = [
{
Match {
HTTP {
PathExact = "/foo"
Header = [
{
Name = "debug1"
Present = true
},
{
Name = "debug2"
Present = false
Invert = true
},
{
Name = "debug3"
Exact = "1"
},
{
Name = "debug4"
Prefix = "aaa"
},
{
Name = "debug5"
Suffix = "bbb"
},
{
Name = "debug6"
Regex = "a.*z"
},
]
}
}
Destination {
Service = "carrot"
ServiceSubset = "kale"
Namespace = "leek"
2021-12-06 18:58:33 +00:00
Partition = "chard"
PrefixRewrite = "/alternate"
RequestTimeout = "99s"
NumRetries = 12345
RetryOnConnectFailure = true
RetryOnStatusCodes = [401, 209]
}
},
{
Match {
HTTP {
PathPrefix = "/foo"
Methods = [ "GET", "DELETE" ]
QueryParam = [
{
Name = "hack1"
Present = true
},
{
Name = "hack2"
Exact = "1"
},
{
Name = "hack3"
Regex = "a.*z"
},
]
}
}
},
{
Match {
HTTP {
PathRegex = "/foo"
}
}
},
]
`,
snakeJSON: `
{
"kind": "service-router",
"name": "main",
2021-12-06 18:58:33 +00:00
"partition": "pepper",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"routes": [
{
"match": {
"http": {
"path_exact": "/foo",
"header": [
{
"name": "debug1",
"present": true
},
{
"name": "debug2",
"present": false,
"invert": true
},
{
"name": "debug3",
"exact": "1"
},
{
"name": "debug4",
"prefix": "aaa"
},
{
"name": "debug5",
"suffix": "bbb"
},
{
"name": "debug6",
"regex": "a.*z"
}
]
}
},
"destination": {
"service": "carrot",
"service_subset": "kale",
"namespace": "leek",
2021-12-06 18:58:33 +00:00
"partition": "chard",
"prefix_rewrite": "/alternate",
"request_timeout": "99s",
"num_retries": 12345,
"retry_on_connect_failure": true,
"retry_on_status_codes": [
401,
209
]
}
},
{
"match": {
"http": {
"path_prefix": "/foo",
"methods": [
"GET",
"DELETE"
],
"query_param": [
{
"name": "hack1",
"present": true
},
{
"name": "hack2",
"exact": "1"
},
{
"name": "hack3",
"regex": "a.*z"
}
]
}
}
},
{
"match": {
"http": {
"path_regex": "/foo"
}
}
}
]
}
`,
camelJSON: `
{
"Kind": "service-router",
"Name": "main",
2021-12-06 18:58:33 +00:00
"Partition": "pepper",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"Routes": [
{
"Match": {
"HTTP": {
"PathExact": "/foo",
"Header": [
{
"Name": "debug1",
"Present": true
},
{
"Name": "debug2",
"Present": false,
"Invert": true
},
{
"Name": "debug3",
"Exact": "1"
},
{
"Name": "debug4",
"Prefix": "aaa"
},
{
"Name": "debug5",
"Suffix": "bbb"
},
{
"Name": "debug6",
"Regex": "a.*z"
}
]
}
},
"Destination": {
"Service": "carrot",
"ServiceSubset": "kale",
"Namespace": "leek",
2021-12-06 18:58:33 +00:00
"Partition": "chard",
"PrefixRewrite": "/alternate",
"RequestTimeout": "99s",
"NumRetries": 12345,
"RetryOnConnectFailure": true,
"RetryOnStatusCodes": [
401,
209
]
}
},
{
"Match": {
"HTTP": {
"PathPrefix": "/foo",
"Methods": [
"GET",
"DELETE"
],
"QueryParam": [
{
"Name": "hack1",
"Present": true
},
{
"Name": "hack2",
"Exact": "1"
},
{
"Name": "hack3",
"Regex": "a.*z"
}
]
}
}
},
{
"Match": {
"HTTP": {
"PathRegex": "/foo"
}
}
}
]
}
`,
expect: &api.ServiceRouterConfigEntry{
2021-12-06 18:58:33 +00:00
Kind: "service-router",
Name: "main",
Partition: "pepper",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Routes: []api.ServiceRoute{
{
Match: &api.ServiceRouteMatch{
HTTP: &api.ServiceRouteHTTPMatch{
PathExact: "/foo",
Header: []api.ServiceRouteHTTPMatchHeader{
{
Name: "debug1",
Present: true,
},
{
Name: "debug2",
Present: false,
Invert: true,
},
{
Name: "debug3",
Exact: "1",
},
{
Name: "debug4",
Prefix: "aaa",
},
{
Name: "debug5",
Suffix: "bbb",
},
{
Name: "debug6",
Regex: "a.*z",
},
},
},
},
Destination: &api.ServiceRouteDestination{
Service: "carrot",
ServiceSubset: "kale",
Namespace: "leek",
2021-12-06 18:58:33 +00:00
Partition: "chard",
PrefixRewrite: "/alternate",
RequestTimeout: 99 * time.Second,
NumRetries: 12345,
RetryOnConnectFailure: true,
RetryOnStatusCodes: []uint32{401, 209},
},
},
{
Match: &api.ServiceRouteMatch{
HTTP: &api.ServiceRouteHTTPMatch{
PathPrefix: "/foo",
Methods: []string{"GET", "DELETE"},
QueryParam: []api.ServiceRouteHTTPMatchQueryParam{
{
Name: "hack1",
Present: true,
},
{
Name: "hack2",
Exact: "1",
},
{
Name: "hack3",
Regex: "a.*z",
},
},
},
},
},
{
Match: &api.ServiceRouteMatch{
HTTP: &api.ServiceRouteHTTPMatch{
PathRegex: "/foo",
},
},
},
},
},
},
{
name: "service-splitter: kitchen sink",
snake: `
kind = "service-splitter"
name = "main"
2021-12-06 18:58:33 +00:00
partition = "east"
meta {
"foo" = "bar"
"gir" = "zim"
}
splits = [
{
weight = 97.1
service_subset = "v1"
},
{
weight = 2
service_subset = "v2"
},
{
weight = 0.9
service = "other"
namespace = "alt"
2021-12-06 18:58:33 +00:00
partition = "west"
},
]
`,
camel: `
Kind = "service-splitter"
Name = "main"
2021-12-06 18:58:33 +00:00
Partition = "east"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Splits = [
{
Weight = 97.1
ServiceSubset = "v1"
},
{
Weight = 2,
ServiceSubset = "v2"
},
{
Weight = 0.9
Service = "other"
Namespace = "alt"
2021-12-06 18:58:33 +00:00
Partition = "west"
},
]
`,
snakeJSON: `
{
"kind": "service-splitter",
"name": "main",
2021-12-06 18:58:33 +00:00
"partition": "east",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"splits": [
{
"weight": 97.1,
"service_subset": "v1"
},
{
"weight": 2,
"service_subset": "v2"
},
{
"weight": 0.9,
"service": "other",
2021-12-06 18:58:33 +00:00
"namespace": "alt",
"partition": "west"
}
]
}
`,
camelJSON: `
{
"Kind": "service-splitter",
"Name": "main",
2021-12-06 18:58:33 +00:00
"Partition": "east",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"Splits": [
{
"Weight": 97.1,
"ServiceSubset": "v1"
},
{
"Weight": 2,
"ServiceSubset": "v2"
},
{
"Weight": 0.9,
"Service": "other",
2021-12-06 18:58:33 +00:00
"Namespace": "alt",
"Partition": "west"
}
]
}
`,
expect: &api.ServiceSplitterConfigEntry{
2021-12-06 18:58:33 +00:00
Kind: api.ServiceSplitter,
Name: "main",
Partition: "east",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Splits: []api.ServiceSplit{
{
Weight: 97.1,
ServiceSubset: "v1",
},
{
Weight: 2,
ServiceSubset: "v2",
},
{
Weight: 0.9,
Service: "other",
Namespace: "alt",
2021-12-06 18:58:33 +00:00
Partition: "west",
},
},
},
},
{
name: "service-resolver: subsets with failover",
snake: `
kind = "service-resolver"
name = "main"
meta {
"foo" = "bar"
"gir" = "zim"
}
default_subset = "v1"
connect_timeout = "15s"
subsets = {
"v1" = {
filter = "Service.Meta.version == v1"
},
"v2" = {
filter = "Service.Meta.version == v2"
only_passing = true
},
}
failover = {
"v2" = {
service = "failcopy"
service_subset = "sure"
namespace = "neighbor"
datacenters = ["dc5", "dc14"]
},
"*" = {
datacenters = ["dc7"]
}
}`,
camel: `
Kind = "service-resolver"
Name = "main"
Meta {
"foo" = "bar"
"gir" = "zim"
}
DefaultSubset = "v1"
ConnectTimeout = "15s"
Subsets = {
"v1" = {
Filter = "Service.Meta.version == v1"
},
"v2" = {
Filter = "Service.Meta.version == v2"
OnlyPassing = true
},
}
Failover = {
"v2" = {
Service = "failcopy"
ServiceSubset = "sure"
Namespace = "neighbor"
Datacenters = ["dc5", "dc14"]
},
"*" = {
Datacenters = ["dc7"]
}
}`,
snakeJSON: `
{
"kind": "service-resolver",
"name": "main",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"default_subset": "v1",
"connect_timeout": "15s",
"subsets": {
"v1": {
"filter": "Service.Meta.version == v1"
},
"v2": {
"filter": "Service.Meta.version == v2",
"only_passing": true
}
},
"failover": {
"v2": {
"service": "failcopy",
"service_subset": "sure",
"namespace": "neighbor",
"datacenters": [
"dc5",
"dc14"
]
},
"*": {
"datacenters": [
"dc7"
]
}
}
}
`,
camelJSON: `
{
"Kind": "service-resolver",
"Name": "main",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"DefaultSubset": "v1",
"ConnectTimeout": "15s",
"Subsets": {
"v1": {
"Filter": "Service.Meta.version == v1"
},
"v2": {
"Filter": "Service.Meta.version == v2",
"OnlyPassing": true
}
},
"Failover": {
"v2": {
"Service": "failcopy",
"ServiceSubset": "sure",
"Namespace": "neighbor",
"Datacenters": [
"dc5",
"dc14"
]
},
"*": {
"Datacenters": [
"dc7"
]
}
}
}
`,
expect: &api.ServiceResolverConfigEntry{
Kind: "service-resolver",
Name: "main",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
DefaultSubset: "v1",
ConnectTimeout: 15 * time.Second,
Subsets: map[string]api.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.version == v1",
},
"v2": {
Filter: "Service.Meta.version == v2",
OnlyPassing: true,
},
},
Failover: map[string]api.ServiceResolverFailover{
"v2": {
Service: "failcopy",
ServiceSubset: "sure",
Namespace: "neighbor",
Datacenters: []string{"dc5", "dc14"},
},
"*": {
Datacenters: []string{"dc7"},
},
},
},
},
{
name: "service-resolver: redirect",
snake: `
kind = "service-resolver"
name = "main"
2021-12-06 18:58:33 +00:00
partition = "east"
redirect {
service = "other"
service_subset = "backup"
namespace = "alt"
2021-12-06 18:58:33 +00:00
partition = "west"
datacenter = "dc9"
}
`,
camel: `
Kind = "service-resolver"
Name = "main"
2021-12-06 18:58:33 +00:00
Partition = "east"
Redirect {
Service = "other"
ServiceSubset = "backup"
Namespace = "alt"
2021-12-06 18:58:33 +00:00
Partition = "west"
Datacenter = "dc9"
}
`,
snakeJSON: `
{
"kind": "service-resolver",
"name": "main",
2021-12-06 18:58:33 +00:00
"partition": "east",
"redirect": {
"service": "other",
"service_subset": "backup",
"namespace": "alt",
2021-12-06 18:58:33 +00:00
"partition": "west",
"datacenter": "dc9"
}
}
`,
camelJSON: `
{
"Kind": "service-resolver",
"Name": "main",
2021-12-06 18:58:33 +00:00
"Partition": "east",
"Redirect": {
"Service": "other",
"ServiceSubset": "backup",
"Namespace": "alt",
2021-12-06 18:58:33 +00:00
"Partition": "west",
"Datacenter": "dc9"
}
}
`,
expect: &api.ServiceResolverConfigEntry{
2021-12-06 18:58:33 +00:00
Kind: "service-resolver",
Name: "main",
Partition: "east",
Redirect: &api.ServiceResolverRedirect{
Service: "other",
ServiceSubset: "backup",
Namespace: "alt",
2021-12-06 18:58:33 +00:00
Partition: "west",
Datacenter: "dc9",
},
},
},
{
name: "service-resolver: default",
snake: `
kind = "service-resolver"
name = "main"
`,
camel: `
Kind = "service-resolver"
Name = "main"
`,
snakeJSON: `
{
"kind": "service-resolver",
"name": "main"
}
`,
camelJSON: `
{
"Kind": "service-resolver",
"Name": "main"
}
`,
expect: &api.ServiceResolverConfigEntry{
Kind: "service-resolver",
Name: "main",
},
},
{
name: "service-resolver: envoy hash lb kitchen sink",
snake: `
kind = "service-resolver"
name = "main"
load_balancer = {
2020-09-11 15:21:43 +00:00
policy = "ring_hash"
ring_hash_config = {
minimum_ring_size = 1
maximum_ring_size = 2
}
2020-09-11 15:21:43 +00:00
hash_policies = [
{
field = "cookie"
field_value = "good-cookie"
cookie_config = {
ttl = "1s"
path = "/oven"
}
terminal = true
},
2020-09-12 00:34:03 +00:00
{
field = "cookie"
field_value = "less-good-cookie"
cookie_config = {
session = true
path = "/toaster"
}
terminal = true
},
2020-09-11 15:21:43 +00:00
{
field = "header"
field_value = "x-user-id"
},
{
source_ip = true
}
]
}
`,
camel: `
Kind = "service-resolver"
Name = "main"
LoadBalancer = {
2020-09-11 15:21:43 +00:00
Policy = "ring_hash"
RingHashConfig = {
MinimumRingSize = 1
MaximumRingSize = 2
}
2020-09-11 15:21:43 +00:00
HashPolicies = [
{
Field = "cookie"
FieldValue = "good-cookie"
CookieConfig = {
TTL = "1s"
Path = "/oven"
}
Terminal = true
},
2020-09-12 00:34:03 +00:00
{
Field = "cookie"
FieldValue = "less-good-cookie"
CookieConfig = {
Session = true
Path = "/toaster"
}
Terminal = true
},
2020-09-11 15:21:43 +00:00
{
Field = "header"
FieldValue = "x-user-id"
},
{
SourceIP = true
}
]
}
`,
snakeJSON: `
{
"kind": "service-resolver",
"name": "main",
"load_balancer": {
2020-09-11 15:21:43 +00:00
"policy": "ring_hash",
"ring_hash_config": {
"minimum_ring_size": 1,
"maximum_ring_size": 2
},
"hash_policies": [
{
"field": "cookie",
"field_value": "good-cookie",
"cookie_config": {
"ttl": "1s",
"path": "/oven"
},
2020-09-11 15:21:43 +00:00
"terminal": true
},
2020-09-12 00:34:03 +00:00
{
"field": "cookie",
"field_value": "less-good-cookie",
"cookie_config": {
"session": true,
"path": "/toaster"
},
"terminal": true
},
2020-09-11 15:21:43 +00:00
{
"field": "header",
"field_value": "x-user-id"
},
{
"source_ip": true
}
]
}
}
`,
camelJSON: `
{
"Kind": "service-resolver",
"Name": "main",
"LoadBalancer": {
2020-09-11 15:21:43 +00:00
"Policy": "ring_hash",
"RingHashConfig": {
"MinimumRingSize": 1,
"MaximumRingSize": 2
},
"HashPolicies": [
{
"Field": "cookie",
"FieldValue": "good-cookie",
"CookieConfig": {
"TTL": "1s",
"Path": "/oven"
},
2020-09-11 15:21:43 +00:00
"Terminal": true
},
2020-09-12 00:34:03 +00:00
{
"Field": "cookie",
"FieldValue": "less-good-cookie",
"CookieConfig": {
"Session": true,
"Path": "/toaster"
},
"Terminal": true
},
2020-09-11 15:21:43 +00:00
{
"Field": "header",
"FieldValue": "x-user-id"
},
{
"SourceIP": true
}
]
}
}
`,
expect: &api.ServiceResolverConfigEntry{
Kind: "service-resolver",
Name: "main",
LoadBalancer: &api.LoadBalancer{
2020-09-11 15:21:43 +00:00
Policy: structs.LBPolicyRingHash,
RingHashConfig: &api.RingHashConfig{
MinimumRingSize: 1,
MaximumRingSize: 2,
},
HashPolicies: []api.HashPolicy{
{
Field: structs.HashPolicyCookie,
FieldValue: "good-cookie",
CookieConfig: &api.CookieConfig{
TTL: 1 * time.Second,
Path: "/oven",
},
2020-09-11 15:21:43 +00:00
Terminal: true,
},
2020-09-12 00:34:03 +00:00
{
Field: structs.HashPolicyCookie,
FieldValue: "less-good-cookie",
CookieConfig: &api.CookieConfig{
Session: true,
Path: "/toaster",
},
Terminal: true,
},
2020-09-11 15:21:43 +00:00
{
Field: structs.HashPolicyHeader,
FieldValue: "x-user-id",
},
{
SourceIP: true,
},
},
},
},
},
{
name: "service-resolver: envoy least request kitchen sink",
snake: `
kind = "service-resolver"
name = "main"
load_balancer = {
2020-09-11 15:21:43 +00:00
policy = "least_request"
least_request_config = {
choice_count = 2
}
}
`,
camel: `
Kind = "service-resolver"
Name = "main"
LoadBalancer = {
2020-09-11 15:21:43 +00:00
Policy = "least_request"
LeastRequestConfig = {
ChoiceCount = 2
}
}
`,
snakeJSON: `
{
"kind": "service-resolver",
"name": "main",
"load_balancer": {
2020-09-11 15:21:43 +00:00
"policy": "least_request",
"least_request_config": {
"choice_count": 2
}
}
}
`,
camelJSON: `
{
"Kind": "service-resolver",
"Name": "main",
"LoadBalancer": {
2020-09-11 15:21:43 +00:00
"Policy": "least_request",
"LeastRequestConfig": {
"ChoiceCount": 2
}
}
}
`,
expect: &api.ServiceResolverConfigEntry{
Kind: "service-resolver",
Name: "main",
LoadBalancer: &api.LoadBalancer{
2020-09-11 15:21:43 +00:00
Policy: structs.LBPolicyLeastRequest,
LeastRequestConfig: &api.LeastRequestConfig{
ChoiceCount: 2,
},
},
},
},
{
name: "expose paths: kitchen sink proxy defaults",
snake: `
kind = "proxy-defaults"
name = "global"
expose = {
checks = true
paths = [
{
local_path_port = 8080
listener_port = 21500
path = "/healthz"
protocol = "http2"
},
{
local_path_port = 8000
listener_port = 21501
path = "/metrics"
protocol = "http"
}
]
}`,
camel: `
Kind = "proxy-defaults"
Name = "global"
Expose = {
Checks = true
Paths = [
{
LocalPathPort = 8080
ListenerPort = 21500
Path = "/healthz"
Protocol = "http2"
},
{
LocalPathPort = 8000
ListenerPort = 21501
Path = "/metrics"
Protocol = "http"
}
]
}`,
snakeJSON: `
{
"kind": "proxy-defaults",
"name": "global",
"expose": {
"checks": true,
"paths": [
{
"local_path_port": 8080,
"listener_port": 21500,
"path": "/healthz",
"protocol": "http2"
},
{
"local_path_port": 8000,
"listener_port": 21501,
"path": "/metrics",
"protocol": "http"
}
]
}
}
`,
camelJSON: `
{
"Kind": "proxy-defaults",
"Name": "global",
"Expose": {
"Checks": true,
"Paths": [
{
"LocalPathPort": 8080,
"ListenerPort": 21500,
"Path": "/healthz",
"Protocol": "http2"
},
{
"LocalPathPort": 8000,
"ListenerPort": 21501,
"Path": "/metrics",
"Protocol": "http"
}
]
}
}
`,
expect: &api.ProxyConfigEntry{
Kind: "proxy-defaults",
Name: "global",
Expose: api.ExposeConfig{
Checks: true,
Paths: []api.ExposePath{
{
ListenerPort: 21500,
Path: "/healthz",
LocalPathPort: 8080,
Protocol: "http2",
},
{
ListenerPort: 21501,
Path: "/metrics",
LocalPathPort: 8000,
Protocol: "http",
},
},
},
},
},
{
name: "expose paths: kitchen sink service defaults",
snake: `
kind = "service-defaults"
name = "web"
expose = {
checks = true
paths = [
{
local_path_port = 8080
listener_port = 21500
path = "/healthz"
protocol = "http2"
},
{
local_path_port = 8000
listener_port = 21501
path = "/metrics"
protocol = "http"
}
]
}`,
camel: `
Kind = "service-defaults"
Name = "web"
Expose = {
Checks = true
Paths = [
{
LocalPathPort = 8080
ListenerPort = 21500
Path = "/healthz"
Protocol = "http2"
},
{
LocalPathPort = 8000
ListenerPort = 21501
Path = "/metrics"
Protocol = "http"
}
]
}`,
snakeJSON: `
{
"kind": "service-defaults",
"name": "web",
"expose": {
"checks": true,
"paths": [
{
"local_path_port": 8080,
"listener_port": 21500,
"path": "/healthz",
"protocol": "http2"
},
{
"local_path_port": 8000,
"listener_port": 21501,
"path": "/metrics",
"protocol": "http"
}
]
}
}
`,
camelJSON: `
{
"Kind": "service-defaults",
"Name": "web",
"Expose": {
"Checks": true,
"Paths": [
{
"LocalPathPort": 8080,
"ListenerPort": 21500,
"Path": "/healthz",
"Protocol": "http2"
},
{
"LocalPathPort": 8000,
"ListenerPort": 21501,
"Path": "/metrics",
"Protocol": "http"
}
]
}
}
`,
expect: &api.ServiceConfigEntry{
Kind: "service-defaults",
Name: "web",
Expose: api.ExposeConfig{
Checks: true,
Paths: []api.ExposePath{
{
ListenerPort: 21500,
Path: "/healthz",
LocalPathPort: 8080,
Protocol: "http2",
},
{
ListenerPort: 21501,
Path: "/metrics",
LocalPathPort: 8000,
Protocol: "http",
},
},
},
},
},
{
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries (#11576) * xds: refactor ingress listener SDS configuration * xds: update resolveListenerSDS call args in listeners_test * ingress: add TLS min, max and cipher suites to GatewayTLSConfig * xds: implement envoyTLSVersions and envoyTLSCipherSuites * xds: merge TLS config * xds: configure TLS parameters with ingress TLS context from leaf * xds: nil check in resolveListenerTLSConfig validation * xds: nil check in makeTLSParameters* functions * changelog: add entry for TLS params on ingress config entries * xds: remove indirection for TLS params in TLSConfig structs * xds: return tlsContext, nil instead of ambiguous err Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * xds: switch zero checks to types.TLSVersionUnspecified * ingress: add validation for ingress config entry TLS params * ingress: validate listener TLS config * xds: add basic ingress with TLS params tests * xds: add ingress listeners mixed TLS min version defaults precedence test * xds: add more explicit tests for ingress listeners inheriting gateway defaults * xds: add test for single TLS listener on gateway without TLS defaults * xds: regen golden files for TLSVersionInvalid zero value, add TLSVersionAuto listener test * types/tls: change TLSVersion to string * types/tls: update TLSCipherSuite to string type * types/tls: implement validation functions for TLSVersion and TLSCipherSuites, make some maps private * api: add TLS params to GatewayTLSConfig, add tests * api: add TLSMinVersion to ingress gateway config entry test JSON * xds: switch to Envoy TLS cipher suite encoding from types package * xds: fixup validation for TLSv1_3 min version with cipher suites * add some kitchen sink tests and add a missing struct tag * xds: check if mergedCfg.TLSVersion is in TLSVersionsWithConfigurableCipherSuites * xds: update connectTLSEnabled comment * xds: remove unsued resolveGatewayServiceTLSConfig function * xds: add makeCommonTLSContextFromLeafWithoutParams * types/tls: add LessThan comparator function for concrete values * types/tls: change tlsVersions validation map from string to TLSVersion keys * types/tls: remove unused envoyTLSCipherSuites * types/tls: enable chacha20 cipher suites for Consul agent * types/tls: remove insecure cipher suites from allowed config TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 are both explicitly listed as insecure and disabled in the Go source. Refs https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330 * types/tls: add ValidateConsulAgentCipherSuites function, make direct lookup map private * types/tls: return all unmatched cipher suites in validation errors * xds: check that Envoy API value matching TLS version is found when building TlsParameters * types/tls: check that value is found in map before appending to slice in MarshalEnvoyTLSCipherSuiteStrings * types/tls: cast to string rather than fmt.Printf in TLSCihperSuite.String() * xds: add TLSVersionUnspecified to list of configurable cipher suites * structs: update note about config entry warning * xds: remove TLS min version cipher suite unconfigurable test placeholder * types/tls: update tests to remove assumption about private map values Co-authored-by: R.B. Boyer <rb@hashicorp.com>
2022-01-11 16:46:42 +00:00
// TODO(rb): test SDS stuff here in both places (global/service)
name: "ingress-gateway: kitchen sink",
snake: `
kind = "ingress-gateway"
name = "ingress-web"
meta {
"foo" = "bar"
"gir" = "zim"
}
tls {
enabled = true
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries (#11576) * xds: refactor ingress listener SDS configuration * xds: update resolveListenerSDS call args in listeners_test * ingress: add TLS min, max and cipher suites to GatewayTLSConfig * xds: implement envoyTLSVersions and envoyTLSCipherSuites * xds: merge TLS config * xds: configure TLS parameters with ingress TLS context from leaf * xds: nil check in resolveListenerTLSConfig validation * xds: nil check in makeTLSParameters* functions * changelog: add entry for TLS params on ingress config entries * xds: remove indirection for TLS params in TLSConfig structs * xds: return tlsContext, nil instead of ambiguous err Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * xds: switch zero checks to types.TLSVersionUnspecified * ingress: add validation for ingress config entry TLS params * ingress: validate listener TLS config * xds: add basic ingress with TLS params tests * xds: add ingress listeners mixed TLS min version defaults precedence test * xds: add more explicit tests for ingress listeners inheriting gateway defaults * xds: add test for single TLS listener on gateway without TLS defaults * xds: regen golden files for TLSVersionInvalid zero value, add TLSVersionAuto listener test * types/tls: change TLSVersion to string * types/tls: update TLSCipherSuite to string type * types/tls: implement validation functions for TLSVersion and TLSCipherSuites, make some maps private * api: add TLS params to GatewayTLSConfig, add tests * api: add TLSMinVersion to ingress gateway config entry test JSON * xds: switch to Envoy TLS cipher suite encoding from types package * xds: fixup validation for TLSv1_3 min version with cipher suites * add some kitchen sink tests and add a missing struct tag * xds: check if mergedCfg.TLSVersion is in TLSVersionsWithConfigurableCipherSuites * xds: update connectTLSEnabled comment * xds: remove unsued resolveGatewayServiceTLSConfig function * xds: add makeCommonTLSContextFromLeafWithoutParams * types/tls: add LessThan comparator function for concrete values * types/tls: change tlsVersions validation map from string to TLSVersion keys * types/tls: remove unused envoyTLSCipherSuites * types/tls: enable chacha20 cipher suites for Consul agent * types/tls: remove insecure cipher suites from allowed config TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 are both explicitly listed as insecure and disabled in the Go source. Refs https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330 * types/tls: add ValidateConsulAgentCipherSuites function, make direct lookup map private * types/tls: return all unmatched cipher suites in validation errors * xds: check that Envoy API value matching TLS version is found when building TlsParameters * types/tls: check that value is found in map before appending to slice in MarshalEnvoyTLSCipherSuiteStrings * types/tls: cast to string rather than fmt.Printf in TLSCihperSuite.String() * xds: add TLSVersionUnspecified to list of configurable cipher suites * structs: update note about config entry warning * xds: remove TLS min version cipher suite unconfigurable test placeholder * types/tls: update tests to remove assumption about private map values Co-authored-by: R.B. Boyer <rb@hashicorp.com>
2022-01-11 16:46:42 +00:00
tls_min_version = "TLSv1_1"
tls_max_version = "TLSv1_2"
cipher_suites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
listeners = [
{
port = 8080
protocol = "http"
services = [
{
name = "web"
hosts = ["test.example.com"]
},
{
name = "db"
namespace = "foo"
}
]
}
]
`,
camel: `
Kind = "ingress-gateway"
Name = "ingress-web"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Tls {
Enabled = true
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries (#11576) * xds: refactor ingress listener SDS configuration * xds: update resolveListenerSDS call args in listeners_test * ingress: add TLS min, max and cipher suites to GatewayTLSConfig * xds: implement envoyTLSVersions and envoyTLSCipherSuites * xds: merge TLS config * xds: configure TLS parameters with ingress TLS context from leaf * xds: nil check in resolveListenerTLSConfig validation * xds: nil check in makeTLSParameters* functions * changelog: add entry for TLS params on ingress config entries * xds: remove indirection for TLS params in TLSConfig structs * xds: return tlsContext, nil instead of ambiguous err Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * xds: switch zero checks to types.TLSVersionUnspecified * ingress: add validation for ingress config entry TLS params * ingress: validate listener TLS config * xds: add basic ingress with TLS params tests * xds: add ingress listeners mixed TLS min version defaults precedence test * xds: add more explicit tests for ingress listeners inheriting gateway defaults * xds: add test for single TLS listener on gateway without TLS defaults * xds: regen golden files for TLSVersionInvalid zero value, add TLSVersionAuto listener test * types/tls: change TLSVersion to string * types/tls: update TLSCipherSuite to string type * types/tls: implement validation functions for TLSVersion and TLSCipherSuites, make some maps private * api: add TLS params to GatewayTLSConfig, add tests * api: add TLSMinVersion to ingress gateway config entry test JSON * xds: switch to Envoy TLS cipher suite encoding from types package * xds: fixup validation for TLSv1_3 min version with cipher suites * add some kitchen sink tests and add a missing struct tag * xds: check if mergedCfg.TLSVersion is in TLSVersionsWithConfigurableCipherSuites * xds: update connectTLSEnabled comment * xds: remove unsued resolveGatewayServiceTLSConfig function * xds: add makeCommonTLSContextFromLeafWithoutParams * types/tls: add LessThan comparator function for concrete values * types/tls: change tlsVersions validation map from string to TLSVersion keys * types/tls: remove unused envoyTLSCipherSuites * types/tls: enable chacha20 cipher suites for Consul agent * types/tls: remove insecure cipher suites from allowed config TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 are both explicitly listed as insecure and disabled in the Go source. Refs https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330 * types/tls: add ValidateConsulAgentCipherSuites function, make direct lookup map private * types/tls: return all unmatched cipher suites in validation errors * xds: check that Envoy API value matching TLS version is found when building TlsParameters * types/tls: check that value is found in map before appending to slice in MarshalEnvoyTLSCipherSuiteStrings * types/tls: cast to string rather than fmt.Printf in TLSCihperSuite.String() * xds: add TLSVersionUnspecified to list of configurable cipher suites * structs: update note about config entry warning * xds: remove TLS min version cipher suite unconfigurable test placeholder * types/tls: update tests to remove assumption about private map values Co-authored-by: R.B. Boyer <rb@hashicorp.com>
2022-01-11 16:46:42 +00:00
TLSMinVersion = "TLSv1_1"
TLSMaxVersion = "TLSv1_2"
CipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
Listeners = [
{
Port = 8080
Protocol = "http"
Services = [
{
Name = "web"
Hosts = ["test.example.com"]
},
{
Name = "db"
Namespace = "foo"
}
]
}
]
`,
snakeJSON: `
{
"kind": "ingress-gateway",
"name": "ingress-web",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"tls": {
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries (#11576) * xds: refactor ingress listener SDS configuration * xds: update resolveListenerSDS call args in listeners_test * ingress: add TLS min, max and cipher suites to GatewayTLSConfig * xds: implement envoyTLSVersions and envoyTLSCipherSuites * xds: merge TLS config * xds: configure TLS parameters with ingress TLS context from leaf * xds: nil check in resolveListenerTLSConfig validation * xds: nil check in makeTLSParameters* functions * changelog: add entry for TLS params on ingress config entries * xds: remove indirection for TLS params in TLSConfig structs * xds: return tlsContext, nil instead of ambiguous err Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * xds: switch zero checks to types.TLSVersionUnspecified * ingress: add validation for ingress config entry TLS params * ingress: validate listener TLS config * xds: add basic ingress with TLS params tests * xds: add ingress listeners mixed TLS min version defaults precedence test * xds: add more explicit tests for ingress listeners inheriting gateway defaults * xds: add test for single TLS listener on gateway without TLS defaults * xds: regen golden files for TLSVersionInvalid zero value, add TLSVersionAuto listener test * types/tls: change TLSVersion to string * types/tls: update TLSCipherSuite to string type * types/tls: implement validation functions for TLSVersion and TLSCipherSuites, make some maps private * api: add TLS params to GatewayTLSConfig, add tests * api: add TLSMinVersion to ingress gateway config entry test JSON * xds: switch to Envoy TLS cipher suite encoding from types package * xds: fixup validation for TLSv1_3 min version with cipher suites * add some kitchen sink tests and add a missing struct tag * xds: check if mergedCfg.TLSVersion is in TLSVersionsWithConfigurableCipherSuites * xds: update connectTLSEnabled comment * xds: remove unsued resolveGatewayServiceTLSConfig function * xds: add makeCommonTLSContextFromLeafWithoutParams * types/tls: add LessThan comparator function for concrete values * types/tls: change tlsVersions validation map from string to TLSVersion keys * types/tls: remove unused envoyTLSCipherSuites * types/tls: enable chacha20 cipher suites for Consul agent * types/tls: remove insecure cipher suites from allowed config TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 are both explicitly listed as insecure and disabled in the Go source. Refs https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330 * types/tls: add ValidateConsulAgentCipherSuites function, make direct lookup map private * types/tls: return all unmatched cipher suites in validation errors * xds: check that Envoy API value matching TLS version is found when building TlsParameters * types/tls: check that value is found in map before appending to slice in MarshalEnvoyTLSCipherSuiteStrings * types/tls: cast to string rather than fmt.Printf in TLSCihperSuite.String() * xds: add TLSVersionUnspecified to list of configurable cipher suites * structs: update note about config entry warning * xds: remove TLS min version cipher suite unconfigurable test placeholder * types/tls: update tests to remove assumption about private map values Co-authored-by: R.B. Boyer <rb@hashicorp.com>
2022-01-11 16:46:42 +00:00
"enabled": true,
"tls_min_version": "TLSv1_1",
"tls_max_version": "TLSv1_2",
"cipher_suites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"listeners": [
{
"port": 8080,
"protocol": "http",
"services": [
{
"name": "web",
"hosts": ["test.example.com"]
},
{
"name": "db",
"namespace": "foo"
}
]
}
]
}
`,
camelJSON: `
{
"Kind": "ingress-gateway",
"Name": "ingress-web",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries (#11576) * xds: refactor ingress listener SDS configuration * xds: update resolveListenerSDS call args in listeners_test * ingress: add TLS min, max and cipher suites to GatewayTLSConfig * xds: implement envoyTLSVersions and envoyTLSCipherSuites * xds: merge TLS config * xds: configure TLS parameters with ingress TLS context from leaf * xds: nil check in resolveListenerTLSConfig validation * xds: nil check in makeTLSParameters* functions * changelog: add entry for TLS params on ingress config entries * xds: remove indirection for TLS params in TLSConfig structs * xds: return tlsContext, nil instead of ambiguous err Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * xds: switch zero checks to types.TLSVersionUnspecified * ingress: add validation for ingress config entry TLS params * ingress: validate listener TLS config * xds: add basic ingress with TLS params tests * xds: add ingress listeners mixed TLS min version defaults precedence test * xds: add more explicit tests for ingress listeners inheriting gateway defaults * xds: add test for single TLS listener on gateway without TLS defaults * xds: regen golden files for TLSVersionInvalid zero value, add TLSVersionAuto listener test * types/tls: change TLSVersion to string * types/tls: update TLSCipherSuite to string type * types/tls: implement validation functions for TLSVersion and TLSCipherSuites, make some maps private * api: add TLS params to GatewayTLSConfig, add tests * api: add TLSMinVersion to ingress gateway config entry test JSON * xds: switch to Envoy TLS cipher suite encoding from types package * xds: fixup validation for TLSv1_3 min version with cipher suites * add some kitchen sink tests and add a missing struct tag * xds: check if mergedCfg.TLSVersion is in TLSVersionsWithConfigurableCipherSuites * xds: update connectTLSEnabled comment * xds: remove unsued resolveGatewayServiceTLSConfig function * xds: add makeCommonTLSContextFromLeafWithoutParams * types/tls: add LessThan comparator function for concrete values * types/tls: change tlsVersions validation map from string to TLSVersion keys * types/tls: remove unused envoyTLSCipherSuites * types/tls: enable chacha20 cipher suites for Consul agent * types/tls: remove insecure cipher suites from allowed config TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 are both explicitly listed as insecure and disabled in the Go source. Refs https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330 * types/tls: add ValidateConsulAgentCipherSuites function, make direct lookup map private * types/tls: return all unmatched cipher suites in validation errors * xds: check that Envoy API value matching TLS version is found when building TlsParameters * types/tls: check that value is found in map before appending to slice in MarshalEnvoyTLSCipherSuiteStrings * types/tls: cast to string rather than fmt.Printf in TLSCihperSuite.String() * xds: add TLSVersionUnspecified to list of configurable cipher suites * structs: update note about config entry warning * xds: remove TLS min version cipher suite unconfigurable test placeholder * types/tls: update tests to remove assumption about private map values Co-authored-by: R.B. Boyer <rb@hashicorp.com>
2022-01-11 16:46:42 +00:00
"TLS": {
"Enabled": true,
"TLSMinVersion": "TLSv1_1",
"TLSMaxVersion": "TLSv1_2",
"CipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"Listeners": [
{
"Port": 8080,
"Protocol": "http",
"Services": [
{
"Name": "web",
"Hosts": ["test.example.com"]
},
{
"Name": "db",
"Namespace": "foo"
}
]
}
]
}
`,
expect: &api.IngressGatewayConfigEntry{
Kind: "ingress-gateway",
Name: "ingress-web",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
TLS: api.GatewayTLSConfig{
ingress: allow setting TLS min version and cipher suites in ingress gateway config entries (#11576) * xds: refactor ingress listener SDS configuration * xds: update resolveListenerSDS call args in listeners_test * ingress: add TLS min, max and cipher suites to GatewayTLSConfig * xds: implement envoyTLSVersions and envoyTLSCipherSuites * xds: merge TLS config * xds: configure TLS parameters with ingress TLS context from leaf * xds: nil check in resolveListenerTLSConfig validation * xds: nil check in makeTLSParameters* functions * changelog: add entry for TLS params on ingress config entries * xds: remove indirection for TLS params in TLSConfig structs * xds: return tlsContext, nil instead of ambiguous err Co-authored-by: Chris S. Kim <ckim@hashicorp.com> * xds: switch zero checks to types.TLSVersionUnspecified * ingress: add validation for ingress config entry TLS params * ingress: validate listener TLS config * xds: add basic ingress with TLS params tests * xds: add ingress listeners mixed TLS min version defaults precedence test * xds: add more explicit tests for ingress listeners inheriting gateway defaults * xds: add test for single TLS listener on gateway without TLS defaults * xds: regen golden files for TLSVersionInvalid zero value, add TLSVersionAuto listener test * types/tls: change TLSVersion to string * types/tls: update TLSCipherSuite to string type * types/tls: implement validation functions for TLSVersion and TLSCipherSuites, make some maps private * api: add TLS params to GatewayTLSConfig, add tests * api: add TLSMinVersion to ingress gateway config entry test JSON * xds: switch to Envoy TLS cipher suite encoding from types package * xds: fixup validation for TLSv1_3 min version with cipher suites * add some kitchen sink tests and add a missing struct tag * xds: check if mergedCfg.TLSVersion is in TLSVersionsWithConfigurableCipherSuites * xds: update connectTLSEnabled comment * xds: remove unsued resolveGatewayServiceTLSConfig function * xds: add makeCommonTLSContextFromLeafWithoutParams * types/tls: add LessThan comparator function for concrete values * types/tls: change tlsVersions validation map from string to TLSVersion keys * types/tls: remove unused envoyTLSCipherSuites * types/tls: enable chacha20 cipher suites for Consul agent * types/tls: remove insecure cipher suites from allowed config TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 are both explicitly listed as insecure and disabled in the Go source. Refs https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/tls/cipher_suites.go;l=329-330 * types/tls: add ValidateConsulAgentCipherSuites function, make direct lookup map private * types/tls: return all unmatched cipher suites in validation errors * xds: check that Envoy API value matching TLS version is found when building TlsParameters * types/tls: check that value is found in map before appending to slice in MarshalEnvoyTLSCipherSuiteStrings * types/tls: cast to string rather than fmt.Printf in TLSCihperSuite.String() * xds: add TLSVersionUnspecified to list of configurable cipher suites * structs: update note about config entry warning * xds: remove TLS min version cipher suite unconfigurable test placeholder * types/tls: update tests to remove assumption about private map values Co-authored-by: R.B. Boyer <rb@hashicorp.com>
2022-01-11 16:46:42 +00:00
Enabled: true,
TLSMinVersion: "TLSv1_1",
TLSMaxVersion: "TLSv1_2",
CipherSuites: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
},
},
Listeners: []api.IngressListener{
{
Port: 8080,
Protocol: "http",
Services: []api.IngressService{
{
Name: "web",
Hosts: []string{"test.example.com"},
},
{
Name: "db",
Namespace: "foo",
},
},
},
},
},
},
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
{
name: "service-intentions: kitchen sink",
snake: `
kind = "service-intentions"
name = "web"
meta {
"foo" = "bar"
"gir" = "zim"
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
}
sources = [
{
name = "foo"
action = "deny"
type = "consul"
description = "foo desc"
},
{
name = "bar"
action = "allow"
description = "bar desc"
},
{
name = "l7"
permissions = [
{
action = "deny"
http {
path_exact = "/admin"
header = [
{
name = "hdr-present"
present = true
},
{
name = "hdr-exact"
exact = "exact"
},
{
name = "hdr-prefix"
prefix = "prefix"
},
{
name = "hdr-suffix"
suffix = "suffix"
},
{
name = "hdr-regex"
regex = "regex"
},
{
name = "hdr-absent"
present = true
invert = true
}
]
}
},
{
action = "allow"
http {
path_prefix = "/v3/"
}
},
{
action = "allow"
http {
path_regex = "/v[12]/.*"
methods = ["GET", "POST"]
}
}
]
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
}
]
sources {
name = "*"
action = "deny"
description = "wild desc"
}
`,
camel: `
Kind = "service-intentions"
Name = "web"
Meta {
"foo" = "bar"
"gir" = "zim"
}
Sources = [
{
Name = "foo"
Action = "deny"
Type = "consul"
Description = "foo desc"
},
{
Name = "bar"
Action = "allow"
Description = "bar desc"
},
{
Name = "l7"
Permissions = [
{
Action = "deny"
HTTP {
PathExact = "/admin"
Header = [
{
Name = "hdr-present"
Present = true
},
{
Name = "hdr-exact"
Exact = "exact"
},
{
Name = "hdr-prefix"
Prefix = "prefix"
},
{
Name = "hdr-suffix"
Suffix = "suffix"
},
{
Name = "hdr-regex"
Regex = "regex"
},
{
Name = "hdr-absent"
Present = true
Invert = true
}
]
}
},
{
Action = "allow"
HTTP {
PathPrefix = "/v3/"
}
},
{
Action = "allow"
HTTP {
PathRegex = "/v[12]/.*"
Methods = ["GET", "POST"]
}
}
]
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
}
]
Sources {
Name = "*"
Action = "deny"
Description = "wild desc"
}
`,
snakeJSON: `
{
"kind": "service-intentions",
"name": "web",
"meta": {
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
"foo": "bar",
"gir": "zim"
},
"sources": [
{
"name": "foo",
"action": "deny",
"type": "consul",
"description": "foo desc"
},
{
"name": "bar",
"action": "allow",
"description": "bar desc"
},
{
"name": "l7",
"permissions": [
{
"action": "deny",
"http": {
"path_exact": "/admin",
"header": [
{
"name": "hdr-present",
"present": true
},
{
"name": "hdr-exact",
"exact": "exact"
},
{
"name": "hdr-prefix",
"prefix": "prefix"
},
{
"name": "hdr-suffix",
"suffix": "suffix"
},
{
"name": "hdr-regex",
"regex": "regex"
},
{
"name": "hdr-absent",
"present": true,
"invert": true
}
]
}
},
{
"action": "allow",
"http": {
"path_prefix": "/v3/"
}
},
{
"action": "allow",
"http": {
"path_regex": "/v[12]/.*",
"methods": [
"GET",
"POST"
]
}
}
]
},
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
{
"name": "*",
"action": "deny",
"description": "wild desc"
}
]
}
`,
camelJSON: `
{
"Kind": "service-intentions",
"Name": "web",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"Sources": [
{
"Name": "foo",
"Action": "deny",
"Type": "consul",
"Description": "foo desc"
},
{
"Name": "bar",
"Action": "allow",
"Description": "bar desc"
},
{
"Name": "l7",
"Permissions": [
{
"Action": "deny",
"HTTP": {
"PathExact": "/admin",
"Header": [
{
"Name": "hdr-present",
"Present": true
},
{
"Name": "hdr-exact",
"Exact": "exact"
},
{
"Name": "hdr-prefix",
"Prefix": "prefix"
},
{
"Name": "hdr-suffix",
"Suffix": "suffix"
},
{
"Name": "hdr-regex",
"Regex": "regex"
},
{
"Name": "hdr-absent",
"Present": true,
"Invert": true
}
]
}
},
{
"Action": "allow",
"HTTP": {
"PathPrefix": "/v3/"
}
},
{
"Action": "allow",
"HTTP": {
"PathRegex": "/v[12]/.*",
"Methods": [
"GET",
"POST"
]
}
}
]
},
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
{
"Name": "*",
"Action": "deny",
"Description": "wild desc"
}
]
}
`,
expect: &api.ServiceIntentionsConfigEntry{
Kind: "service-intentions",
Name: "web",
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Sources: []*api.SourceIntention{
{
Name: "foo",
Action: "deny",
Type: "consul",
Description: "foo desc",
},
{
Name: "bar",
Action: "allow",
Description: "bar desc",
},
{
Name: "l7",
Permissions: []*api.IntentionPermission{
{
Action: "deny",
HTTP: &api.IntentionHTTPPermission{
PathExact: "/admin",
Header: []api.IntentionHTTPHeaderPermission{
{
Name: "hdr-present",
Present: true,
},
{
Name: "hdr-exact",
Exact: "exact",
},
{
Name: "hdr-prefix",
Prefix: "prefix",
},
{
Name: "hdr-suffix",
Suffix: "suffix",
},
{
Name: "hdr-regex",
Regex: "regex",
},
{
Name: "hdr-absent",
Present: true,
Invert: true,
},
},
},
},
{
Action: "allow",
HTTP: &api.IntentionHTTPPermission{
PathPrefix: "/v3/",
},
},
{
Action: "allow",
HTTP: &api.IntentionHTTPPermission{
PathRegex: "/v[12]/.*",
Methods: []string{"GET", "POST"},
},
},
},
},
connect: intentions are now managed as a new config entry kind "service-intentions" (#8834) - Upgrade the ConfigEntry.ListAll RPC to be kind-aware so that older copies of consul will not see new config entries it doesn't understand replicate down. - Add shim conversion code so that the old API/CLI method of interacting with intentions will continue to work so long as none of these are edited via config entry endpoints. Almost all of the read-only APIs will continue to function indefinitely. - Add new APIs that operate on individual intentions without IDs so that the UI doesn't need to implement CAS operations. - Add a new serf feature flag indicating support for intentions-as-config-entries. - The old line-item intentions way of interacting with the state store will transparently flip between the legacy memdb table and the config entry representations so that readers will never see a hiccup during migration where the results are incomplete. It uses a piece of system metadata to control the flip. - The primary datacenter will begin migrating intentions into config entries on startup once all servers in the datacenter are on a version of Consul with the intentions-as-config-entries feature flag. When it is complete the old state store representations will be cleared. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up. - The secondary datacenters continue to run the old intentions replicator until all servers in the secondary DC and primary DC support intentions-as-config-entries (via serf flag). Once this condition it met the old intentions replicator ceases. - The secondary datacenters replicate the new config entries as they are migrated in the primary. When they detect that the primary has zeroed it's old state store table it waits until all config entries up to that point are replicated and then zeroes its own copy of the old state store table. We also record a piece of system metadata indicating this has occurred. We use this metadata to skip ALL of this code the next time the leader starts up.
2020-10-06 18:24:05 +00:00
{
Name: "*",
Action: "deny",
Description: "wild desc",
},
},
},
},
{
name: "service-intentions: wildcard destination",
snake: `
kind = "service-intentions"
name = "*"
sources {
name = "foo"
action = "deny"
# should be parsed, but we'll ignore it later
precedence = 6
}
`,
camel: `
Kind = "service-intentions"
Name = "*"
Sources {
Name = "foo"
Action = "deny"
# should be parsed, but we'll ignore it later
Precedence = 6
}
`,
snakeJSON: `
{
"kind": "service-intentions",
"name": "*",
"sources": [
{
"name": "foo",
"action": "deny",
"precedence": 6
}
]
}
`,
camelJSON: `
{
"Kind": "service-intentions",
"Name": "*",
"Sources": [
{
"Name": "foo",
"Action": "deny",
"Precedence": 6
}
]
}
`,
expect: &api.ServiceIntentionsConfigEntry{
Kind: "service-intentions",
Name: "*",
Sources: []*api.SourceIntention{
{
Name: "foo",
Action: "deny",
Precedence: 6,
},
},
},
},
{
name: "mesh",
snake: `
kind = "mesh"
meta {
"foo" = "bar"
"gir" = "zim"
}
transparent_proxy {
mesh_destinations_only = true
}
tls {
incoming {
tls_min_version = "TLSv1_1"
tls_max_version = "TLSv1_2"
cipher_suites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
outgoing {
tls_min_version = "TLSv1_1"
tls_max_version = "TLSv1_2"
cipher_suites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
}
`,
camel: `
Kind = "mesh"
Meta {
"foo" = "bar"
"gir" = "zim"
}
TransparentProxy {
MeshDestinationsOnly = true
}
TLS {
Incoming {
TLSMinVersion = "TLSv1_1"
TLSMaxVersion = "TLSv1_2"
CipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
Outgoing {
TLSMinVersion = "TLSv1_1"
TLSMaxVersion = "TLSv1_2"
CipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
}
`,
snakeJSON: `
{
"kind": "mesh",
"meta" : {
"foo": "bar",
"gir": "zim"
},
"transparent_proxy": {
"mesh_destinations_only": true
},
"tls": {
"incoming": {
"tls_min_version": "TLSv1_1",
"tls_max_version": "TLSv1_2",
"cipher_suites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"outgoing": {
"tls_min_version": "TLSv1_1",
"tls_max_version": "TLSv1_2",
"cipher_suites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
}
}
`,
camelJSON: `
{
"Kind": "mesh",
"Meta" : {
"foo": "bar",
"gir": "zim"
},
"TransparentProxy": {
"MeshDestinationsOnly": true
},
"TLS": {
"Incoming": {
"TLSMinVersion": "TLSv1_1",
"TLSMaxVersion": "TLSv1_2",
"CipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
},
"Outgoing": {
"TLSMinVersion": "TLSv1_1",
"TLSMaxVersion": "TLSv1_2",
"CipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
]
}
}
}
`,
expect: &api.MeshConfigEntry{
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
TransparentProxy: api.TransparentProxyMeshConfig{
MeshDestinationsOnly: true,
},
TLS: &api.MeshTLSConfig{
Incoming: &api.MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_1",
TLSMaxVersion: "TLSv1_2",
CipherSuites: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
},
},
Outgoing: &api.MeshDirectionalTLSConfig{
TLSMinVersion: "TLSv1_1",
TLSMaxVersion: "TLSv1_2",
CipherSuites: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
},
},
},
},
},
2021-10-20 19:24:18 +00:00
{
name: "exported-services",
2021-10-20 19:24:18 +00:00
snake: `
kind = "exported-services"
name = "foo"
2021-10-20 19:24:18 +00:00
meta {
"foo" = "bar"
"gir" = "zim"
}
services = [
{
name = "web"
namespace = "foo"
consumers = [
{
partition = "bar"
},
{
partition = "baz"
},
{
peer_name = "flarm"
2021-10-20 19:24:18 +00:00
}
]
},
{
name = "db"
namespace = "bar"
consumers = [
{
partition = "zoo"
}
]
}
]
`,
camel: `
Kind = "exported-services"
Name = "foo"
2021-10-20 19:24:18 +00:00
Meta {
"foo" = "bar"
"gir" = "zim"
}
Services = [
{
Name = "web"
Namespace = "foo"
Consumers = [
{
Partition = "bar"
},
{
Partition = "baz"
},
{
PeerName = "flarm"
2021-10-20 19:24:18 +00:00
}
]
},
{
Name = "db"
Namespace = "bar"
Consumers = [
{
Partition = "zoo"
}
]
}
]
`,
snakeJSON: `
{
"kind": "exported-services",
"name": "foo",
2021-10-20 19:24:18 +00:00
"meta": {
"foo": "bar",
"gir": "zim"
},
"services": [
{
"name": "web",
"namespace": "foo",
"consumers": [
{
"partition": "bar"
},
{
"partition": "baz"
},
{
"peer_name": "flarm"
2021-10-20 19:24:18 +00:00
}
]
},
{
"name": "db",
"namespace": "bar",
"consumers": [
{
"partition": "zoo"
}
]
}
]
}
`,
camelJSON: `
{
"Kind": "exported-services",
"Name": "foo",
2021-10-20 19:24:18 +00:00
"Meta": {
"foo": "bar",
"gir": "zim"
},
"Services": [
{
"Name": "web",
"Namespace": "foo",
"Consumers": [
{
"Partition": "bar"
},
{
"Partition": "baz"
},
{
"PeerName": "flarm"
2021-10-20 19:24:18 +00:00
}
]
},
{
"Name": "db",
"Namespace": "bar",
"Consumers": [
{
"Partition": "zoo"
}
]
}
]
}
`,
expect: &api.ExportedServicesConfigEntry{
Name: "foo",
2021-10-20 19:24:18 +00:00
Meta: map[string]string{
"foo": "bar",
"gir": "zim",
},
Services: []api.ExportedService{
{
Name: "web",
Namespace: "foo",
Consumers: []api.ServiceConsumer{
{
Partition: "bar",
},
{
Partition: "baz",
},
{
PeerName: "flarm",
},
2021-10-20 19:24:18 +00:00
},
},
{
Name: "db",
Namespace: "bar",
Consumers: []api.ServiceConsumer{
{
Partition: "zoo",
},
},
},
},
},
},
} {
tc := tc
testbody := func(t *testing.T, body string, expect api.ConfigEntry) {
t.Helper()
got, err := parseConfigEntry(body)
if tc.expectErr != "" {
require.Nil(t, got)
require.Error(t, err)
requireContainsLower(t, err.Error(), tc.expectErr)
} else {
require.NoError(t, err)
require.Equal(t, expect, got)
}
}
t.Run(tc.name+" (hcl snake case)", func(t *testing.T) {
testbody(t, tc.snake, tc.expect)
})
t.Run(tc.name+" (hcl camel case)", func(t *testing.T) {
testbody(t, tc.camel, tc.expect)
})
if tc.snakeJSON != "" {
t.Run(tc.name+" (json snake case)", func(t *testing.T) {
if tc.expectJSON != nil {
testbody(t, tc.snakeJSON, tc.expectJSON)
} else {
testbody(t, tc.snakeJSON, tc.expect)
}
})
}
if tc.camelJSON != "" {
t.Run(tc.name+" (json camel case)", func(t *testing.T) {
if tc.expectJSON != nil {
testbody(t, tc.camelJSON, tc.expectJSON)
} else {
testbody(t, tc.camelJSON, tc.expect)
}
})
}
}
}
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
func requireContainsLower(t *testing.T, haystack, needle string) {
t.Helper()
require.Contains(t, strings.ToLower(haystack), strings.ToLower(needle))
Centralized Config CLI (#5731) * Add HTTP endpoints for config entry management * Finish implementing decoding in the HTTP Config entry apply endpoint * Add CAS operation to the config entry apply endpoint Also use this for the bootstrapping and move the config entry decoding function into the structs package. * First pass at the API client for the config entries * Fixup some of the ConfigEntry APIs Return a singular response object instead of a list for the ConfigEntry.Get RPC. This gets plumbed through the HTTP API as well. Dont return QueryMeta in the JSON response for the config entry listing HTTP API. Instead just return a list of config entries. * Minor API client fixes * Attempt at some ConfigEntry api client tests These don’t currently work due to weak typing in JSON * Get some of the api client tests passing * Implement reflectwalk magic to correct JSON encoding a ProxyConfigEntry Also added a test for the HTTP endpoint that exposes the problem. However, since the test doesn’t actually do the JSON encode/decode its still failing. * Move MapWalk magic into a binary marshaller instead of JSON. * Add a MapWalk test * Get rid of unused func * Get rid of unused imports * Fixup some tests now that the decoding from msgpack coerces things into json compat types * Stub out most of the central config cli Fully implement the config read command. * Basic config delete command implementation * Implement config write command * Implement config list subcommand Not entirely sure about the output here. Its basically the read output indented with a line specifying the kind/name of each type which is also duplicated in the indented output. * Update command usage * Update some help usage formatting * Add the connect enable helper cli command * Update list command output * Rename the config entry API client methods. * Use renamed apis * Implement config write tests Stub the others with the noTabs tests. * Change list output format Now just simply output 1 line per named config * Add config read tests * Add invalid args write test. * Add config delete tests * Add config list tests * Add connect enable tests * Update some CLI commands to use CAS ops This also modifies the HTTP API for a write op to return a boolean indicating whether the value was written or not. * Fix up the HTTP API CAS tests as I realized they weren’t testing what they should. * Update config entry rpc tests to properly test CAS * Fix up a few more tests * Fix some tests that using ConfigEntries.Apply * Update config_write_test.go * Get rid of unused import
2019-04-30 23:27:16 +00:00
}
func intPointer(v int) *int {
return &v
}