Skip to content

Commit

Permalink
NET-5912/service-defaults protocol validation (#21593)
Browse files Browse the repository at this point in the history
* fix: add validation for protocol field on service-defaults config entry

* test: update test cases with correct protocol
  • Loading branch information
JadhavPoonam authored and philrenaud committed Sep 12, 2024
1 parent 80ac29e commit bb00b3e
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 15 deletions.
4 changes: 3 additions & 1 deletion agent/config/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (
"time"

"github.com/armon/go-metrics/prometheus"
"golang.org/x/time/rate"

"github.com/hashicorp/go-bexpr"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-sockaddr/template"
"github.com/hashicorp/memberlist"
"golang.org/x/time/rate"

"github.com/hashicorp/consul/agent/cache"
"github.com/hashicorp/consul/agent/checks"
Expand Down Expand Up @@ -774,6 +775,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
if err != nil {
return RuntimeConfig{}, fmt.Errorf("config_entries.bootstrap[%d]: %s", i, err)
}
// Ensure Normalize is called before Validate for accurate validation
if err := entry.Normalize(); err != nil {
return RuntimeConfig{}, fmt.Errorf("config_entries.bootstrap[%d]: %s", i, err)
}
Expand Down
4 changes: 2 additions & 2 deletions agent/config_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ func TestConfig_Apply_CAS(t *testing.T) {
{
"Kind": "service-defaults",
"Name": "foo",
"Protocol": "udp"
"Protocol": "http"
}
`))
req, _ = http.NewRequest("PUT", "/v1/config?cas=0", body)
Expand All @@ -628,7 +628,7 @@ func TestConfig_Apply_CAS(t *testing.T) {
{
"Kind": "service-defaults",
"Name": "foo",
"Protocol": "udp"
"Protocol": "http"
}
`))
req, _ = http.NewRequest("PUT", fmt.Sprintf("/v1/config?cas=%d", entry.GetRaftIndex().ModifyIndex), body)
Expand Down
4 changes: 3 additions & 1 deletion agent/consul/config_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (

metrics "github.com/armon/go-metrics"
"github.com/armon/go-metrics/prometheus"
hashstructure_v2 "github.com/mitchellh/hashstructure/v2"

"github.com/hashicorp/go-bexpr"
"github.com/hashicorp/go-hclog"
memdb "github.com/hashicorp/go-memdb"
hashstructure_v2 "github.com/mitchellh/hashstructure/v2"

"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/configentry"
Expand Down Expand Up @@ -85,6 +86,7 @@ func (c *ConfigEntry) Apply(args *structs.ConfigEntryRequest, reply *bool) error
}

// Normalize and validate the incoming config entry as if it came from a user.
// Ensure Normalize is called before Validate for accurate validation
if err := args.Entry.Normalize(); err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions agent/consul/config_replication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ package consul
import (
"context"
"fmt"
"github.com/oklog/ulid/v2"
"github.com/stretchr/testify/assert"
"os"
"testing"

"github.com/oklog/ulid/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/hashicorp/consul/agent/structs"
Expand Down Expand Up @@ -129,7 +129,7 @@ func TestReplication_ConfigEntries(t *testing.T) {
Entry: &structs.ServiceConfigEntry{
Kind: structs.ServiceDefaults,
Name: fmt.Sprintf("svc-%d", i),
Protocol: "udp",
Protocol: "tcp",
},
}

Expand Down
9 changes: 7 additions & 2 deletions agent/structs/config_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ import (
"time"

"github.com/miekg/dns"

"github.com/hashicorp/go-multierror"
"github.com/mitchellh/hashstructure"
"github.com/mitchellh/mapstructure"

"github.com/hashicorp/consul-net-rpc/go-msgpack/codec"
"github.com/hashicorp/go-multierror"

"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/cache"
Expand Down Expand Up @@ -269,6 +268,12 @@ func (e *ServiceConfigEntry) Validate() error {
validationErr = multierror.Append(validationErr, fmt.Errorf("invalid value for balance_inbound_connections: %v", e.BalanceInboundConnections))
}

switch e.Protocol {
case "", "http", "http2", "grpc", "tcp":
default:
validationErr = multierror.Append(validationErr, fmt.Errorf("invalid value for protocol: %v", e.Protocol))
}

// External endpoints are invalid with an existing service's upstream configuration
if e.UpstreamConfig != nil && e.Destination != nil {
validationErr = multierror.Append(validationErr, errors.New("UpstreamConfig and Destination are mutually exclusive for service defaults"))
Expand Down
10 changes: 9 additions & 1 deletion agent/structs/config_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
"time"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl"
"github.com/mitchellh/copystructure"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/hashicorp/consul-net-rpc/go-msgpack/codec"
"github.com/hashicorp/hcl"

"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/cache"
Expand Down Expand Up @@ -3225,6 +3225,14 @@ func TestServiceConfigEntry(t *testing.T) {
},
validateErr: `Invalid MutualTLSMode "invalid-mtls-mode". Must be one of "", "strict", or "permissive".`,
},
"validate: invalid Protocol in service-defaults": {
entry: &ServiceConfigEntry{
Kind: ServiceDefaults,
Name: "web",
Protocol: "blah",
},
validateErr: `invalid value for protocol: blah`,
},
}
testConfigEntryNormalizeAndValidate(t, cases)
}
Expand Down
6 changes: 3 additions & 3 deletions api/config_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func TestAPI_ConfigEntries(t *testing.T) {
service := &ServiceConfigEntry{
Kind: ServiceDefaults,
Name: "foo",
Protocol: "udp",
Protocol: "http",
MutualTLSMode: MutualTLSModeStrict,
Meta: map[string]string{
"foo": "bar",
Expand All @@ -124,7 +124,7 @@ func TestAPI_ConfigEntries(t *testing.T) {
service2 := &ServiceConfigEntry{
Kind: ServiceDefaults,
Name: "bar",
Protocol: "tcp",
Protocol: "http",
Destination: dest,
}

Expand Down Expand Up @@ -176,7 +176,7 @@ func TestAPI_ConfigEntries(t *testing.T) {
require.True(t, written)

// update no cas
service.Protocol = "http"
service.Protocol = "tcp"

_, wm, err = config_entries.Set(service, nil)
require.NoError(t, err)
Expand Down
25 changes: 23 additions & 2 deletions command/config/write/config_write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestConfigWrite(t *testing.T) {
_, err := f.WriteString(`
Kind = "service-defaults"
Name = "web"
Protocol = "udp"
Protocol = "tcp"
`)

require.NoError(t, err)
Expand All @@ -65,7 +65,7 @@ func TestConfigWrite(t *testing.T) {
require.True(t, ok)
require.Equal(t, api.ServiceDefaults, svc.Kind)
require.Equal(t, "web", svc.Name)
require.Equal(t, "udp", svc.Protocol)
require.Equal(t, "tcp", svc.Protocol)
})

t.Run("Stdin", func(t *testing.T) {
Expand Down Expand Up @@ -170,6 +170,27 @@ kind = "proxy-defaults"
`Config entry written: proxy-defaults/global`)
require.Equal(t, 0, code)
})

// Test that protocol field is first normalized and then validated
// before writing the config entry
t.Run("service defaults config entry mixed case in protocol field", func(t *testing.T) {
stdin := new(bytes.Buffer)
stdin.WriteString(`
Kind = "service-defaults"
Name = "web"
Protocol = "TcP"
`)

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: service-defaults/web`)
require.Equal(t, 0, code)
})
}

func TestConfigWrite_Warning(t *testing.T) {
Expand Down

0 comments on commit bb00b3e

Please sign in to comment.