From 7c00d396cff930c456ab44253caf8134048d8497 Mon Sep 17 00:00:00 2001 From: Melisa Griffin Date: Wed, 31 Jan 2024 18:47:57 -0500 Subject: [PATCH] [NET-6417] Add validation of MeshGateway name + listeners (#20425) * Add validation of MeshGateway name + listeners * Adds test for ValidateMeshGateway * Fixes data fetcher test for gatewayproxy --------- Co-authored-by: Nathan Coleman --- .../gatewayproxy/fetcher/data_fetcher_test.go | 7 +- internal/mesh/internal/types/mesh_gateway.go | 26 ++++- .../mesh/internal/types/mesh_gateway_test.go | 97 +++++++++++++++++++ 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 internal/mesh/internal/types/mesh_gateway_test.go diff --git a/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go b/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go index e3ec69b6bd..799e76a090 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go +++ b/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go @@ -69,9 +69,14 @@ func (suite *dataFetcherSuite) setupWithTenancy(tenancy *pbresource.Tenancy) { ). Write(suite.T(), suite.client) - suite.meshGateway = resourcetest.Resource(pbmesh.MeshGatewayType, "mesh-gateway-1"). + suite.meshGateway = resourcetest.Resource(pbmesh.MeshGatewayType, "mesh-gateway"). WithData(suite.T(), &pbmesh.MeshGateway{ GatewayClassName: "gateway-class-1", + Listeners: []*pbmesh.MeshGatewayListener{ + { + Name: "wan", + }, + }, }). Write(suite.T(), suite.client) diff --git a/internal/mesh/internal/types/mesh_gateway.go b/internal/mesh/internal/types/mesh_gateway.go index 2583b4dcc0..59c15a231d 100644 --- a/internal/mesh/internal/types/mesh_gateway.go +++ b/internal/mesh/internal/types/mesh_gateway.go @@ -4,6 +4,12 @@ package types import ( + "errors" + "fmt" + + "github.com/hashicorp/go-multierror" + + "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshgateways" "github.com/hashicorp/consul/internal/resource" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" ) @@ -15,6 +21,24 @@ func RegisterMeshGateway(r resource.Registry) { Scope: resource.ScopePartition, ACLs: nil, // TODO NET-6416 Mutate: nil, // TODO NET-6418 - Validate: nil, // TODO NET-6417 + Validate: resource.DecodeAndValidate(validateMeshGateway), }) } + +func validateMeshGateway(res *DecodedMeshGateway) error { + var merr error + + if res.GetId().GetName() != meshgateways.GatewayName { + merr = multierror.Append(merr, fmt.Errorf("invalid gateway name, must be %q", meshgateways.GatewayName)) + } + + if len(res.GetData().Listeners) != 1 { + merr = multierror.Append(merr, errors.New("invalid listeners, must have exactly one listener")) + } + + if len(res.GetData().Listeners) > 0 && (res.GetData().Listeners[0].GetName() != meshgateways.WANPortName) { + merr = multierror.Append(merr, fmt.Errorf("invalid listener name, must be %q", meshgateways.WANPortName)) + } + + return merr +} diff --git a/internal/mesh/internal/types/mesh_gateway_test.go b/internal/mesh/internal/types/mesh_gateway_test.go new file mode 100644 index 0000000000..cb5372355f --- /dev/null +++ b/internal/mesh/internal/types/mesh_gateway_test.go @@ -0,0 +1,97 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "github.com/hashicorp/consul/internal/resource" + "testing" + + "github.com/hashicorp/consul/internal/resource/resourcetest" + pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" + "github.com/hashicorp/consul/sdk/testutil" + "github.com/stretchr/testify/require" +) + +func TestValidateMeshGateway(t *testing.T) { + type testcase struct { + mgwName string + mgw *pbmesh.MeshGateway + expectErr string + } + + run := func(t *testing.T, tc testcase) { + res := resourcetest.Resource(pbmesh.MeshGatewayType, tc.mgwName). + WithData(t, tc.mgw). + Build() + + err := resource.DecodeAndValidate(validateMeshGateway)(res) + + if tc.expectErr == "" { + require.NoError(t, err) + } else { + testutil.RequireErrorContains(t, err, tc.expectErr) + } + } + + cases := map[string]testcase{ + "happy path": { + mgwName: "mesh-gateway", + mgw: &pbmesh.MeshGateway{ + Listeners: []*pbmesh.MeshGatewayListener{ + { + Name: "wan", + }, + }, + }, + expectErr: "", + }, + "wrong name for mesh-gateway": { + mgwName: "my-mesh-gateway", + mgw: &pbmesh.MeshGateway{ + Listeners: []*pbmesh.MeshGatewayListener{ + { + Name: "wan", + }, + }, + }, + expectErr: "invalid gateway name, must be \"mesh-gateway\"", + }, + "too many listeners on mesh-gateway": { + mgwName: "mesh-gateway", + mgw: &pbmesh.MeshGateway{ + Listeners: []*pbmesh.MeshGatewayListener{ + { + Name: "obi", + }, + { + Name: "wan", + }, + }, + }, + expectErr: "invalid listeners, must have exactly one listener", + }, + "zero listeners on mesh-gateway": { + mgwName: "mesh-gateway", + mgw: &pbmesh.MeshGateway{}, + expectErr: "invalid listeners, must have exactly one listener", + }, + "incorrect listener name on mesh-gateway": { + mgwName: "mesh-gateway", + mgw: &pbmesh.MeshGateway{ + Listeners: []*pbmesh.MeshGatewayListener{ + { + Name: "kenobi", + }, + }, + }, + expectErr: "invalid listener name, must be \"wan\"", + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +}