From dc822f95ac01ab84d3eb361fa18d177d8d92c27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20T=C3=B4rres?= Date: Tue, 21 Feb 2023 22:02:15 -0800 Subject: [PATCH 1/2] feat(routing): lookup host without port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pedro Tôrres --- Changelog.md => CHANGELOG.md | 2 +- interceptor/proxy_handlers.go | 2 +- pkg/routing/table.go | 21 +++++++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) rename Changelog.md => CHANGELOG.md (90%) diff --git a/Changelog.md b/CHANGELOG.md similarity index 90% rename from Changelog.md rename to CHANGELOG.md index 6b08d9935..ad3266344 100644 --- a/Changelog.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ This changelog keeps track of work items that have been completed and are ready ### Fixes -- **General**: TODO ([#TODO](https://github.com/kedacore/http-add-on/issues/TODO)) +- **Routing**: Lookup host without port ([#608](https://github.com/kedacore/http-add-on/issues/608)) ### Deprecations diff --git a/interceptor/proxy_handlers.go b/interceptor/proxy_handlers.go index ac94c9ebc..7f7215c61 100644 --- a/interceptor/proxy_handlers.go +++ b/interceptor/proxy_handlers.go @@ -92,7 +92,7 @@ func newForwardingHandler( } return } - targetSvcURL, err := targetSvcURL(routingTarget) + targetSvcURL, err := targetSvcURL(*routingTarget) if err != nil { lggr.Error(err, "forwarding failed") w.WriteHeader(500) diff --git a/pkg/routing/table.go b/pkg/routing/table.go index 005411cec..7cffc984b 100644 --- a/pkg/routing/table.go +++ b/pkg/routing/table.go @@ -4,11 +4,12 @@ import ( "bytes" "encoding/json" "fmt" + "strings" "sync" ) type TableReader interface { - Lookup(string) (Target, error) + Lookup(string) (*Target, error) Hosts() []string HasHost(string) bool } @@ -70,14 +71,22 @@ func (t *Table) UnmarshalJSON(data []byte) error { return json.NewDecoder(b).Decode(&t.m) } -func (t *Table) Lookup(host string) (Target, error) { +func (t *Table) Lookup(host string) (*Target, error) { t.l.RLock() defer t.l.RUnlock() - ret, ok := t.m[host] - if !ok { - return Target{}, ErrTargetNotFound + + keys := []string{host} + if i := strings.LastIndex(host, ":"); i != -1 { + keys = append(keys, host[:i]) } - return ret, nil + + for _, key := range keys { + if target, ok := t.m[key]; ok { + return &target, nil + } + } + + return nil, ErrTargetNotFound } // AddTarget registers target for host in the routing table t From 68e3cd49971b7f2e1633af1380d027c9e2c9a592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20T=C3=B4rres?= Date: Tue, 21 Feb 2023 22:02:40 -0800 Subject: [PATCH 2/2] test(routing): lookup host without port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pedro Tôrres --- operator/controllers/routing_table_test.go | 2 +- pkg/routing/suite_test.go | 13 +++ pkg/routing/table_test.go | 122 ++++++++++++++++++++- 3 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 pkg/routing/suite_test.go diff --git a/operator/controllers/routing_table_test.go b/operator/controllers/routing_table_test.go index 8820501e8..ce0ad5430 100644 --- a/operator/controllers/routing_table_test.go +++ b/operator/controllers/routing_table_test.go @@ -58,7 +58,7 @@ func TestRoutingTable(t *testing.T) { retTarget, err := table.Lookup(host) r.NoError(err) - r.Equal(target, retTarget) + r.Equal(&target, retTarget) r.NoError(removeAndUpdateRoutingTable( ctx, diff --git a/pkg/routing/suite_test.go b/pkg/routing/suite_test.go new file mode 100644 index 000000000..94d53b186 --- /dev/null +++ b/pkg/routing/suite_test.go @@ -0,0 +1,13 @@ +package routing + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestRouting(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Routing Suite") +} diff --git a/pkg/routing/table_test.go b/pkg/routing/table_test.go index 668dd289b..1269d779a 100644 --- a/pkg/routing/table_test.go +++ b/pkg/routing/table_test.go @@ -2,8 +2,13 @@ package routing import ( "encoding/json" + "math" + "math/rand" + "strconv" "testing" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" "github.com/stretchr/testify/require" ) @@ -55,13 +60,13 @@ func TestTableRemove(t *testing.T) { // add the target to the table and ensure that you can look it up r.NoError(tbl.AddTarget(host, tgt)) retTgt, err := tbl.Lookup(host) - r.Equal(tgt, retTgt) + r.Equal(&tgt, retTgt) r.NoError(err) // remove the target and ensure that you can't look it up r.NoError(tbl.RemoveTarget(host)) retTgt, err = tbl.Lookup(host) - r.Equal(Target{}, retTgt) + r.Equal((*Target)(nil), retTgt) r.Equal(ErrTargetNotFound, err) } @@ -96,3 +101,116 @@ func TestTableReplace(t *testing.T) { r.Equal(tbl1, tbl2) } + +var _ = Describe("Table", func() { + Describe("Lookup", func() { + var ( + tltcs = newTableLookupTestCases(5) + table = NewTable() + ) + + Context("with new port-agnostic configuration", func() { + BeforeEach(func() { + for _, tltc := range tltcs { + err := table.AddTarget(tltc.HostWithoutPort(), tltc.Target()) + Expect(err).NotTo(HaveOccurred()) + } + }) + + AfterEach(func() { + for _, tltc := range tltcs { + err := table.RemoveTarget(tltc.HostWithoutPort()) + Expect(err).NotTo(HaveOccurred()) + } + }) + + It("should return correct target for host without port", func() { + for _, tltc := range tltcs { + target, err := table.Lookup(tltc.HostWithoutPort()) + Expect(err).NotTo(HaveOccurred()) + Expect(target).To(HaveValue(Equal(tltc.Target()))) + } + }) + + It("should return correct target for host with port", func() { + for _, tltc := range tltcs { + target, err := table.Lookup(tltc.HostWithPort()) + Expect(err).NotTo(HaveOccurred()) + Expect(target).To(HaveValue(Equal(tltc.Target()))) + } + }) + }) + + Context("with legacy port-specific configuration", func() { + BeforeEach(func() { + for _, tltc := range tltcs { + err := table.AddTarget(tltc.HostWithPort(), tltc.Target()) + Expect(err).NotTo(HaveOccurred()) + } + }) + + AfterEach(func() { + for _, tltc := range tltcs { + err := table.RemoveTarget(tltc.HostWithPort()) + Expect(err).NotTo(HaveOccurred()) + } + }) + + It("should error for host without port", func() { + for _, tltc := range tltcs { + target, err := table.Lookup(tltc.HostWithoutPort()) + Expect(err).To(MatchError(ErrTargetNotFound)) + Expect(target).To(BeNil()) + } + }) + + It("should return correct target for host with port", func() { + for _, tltc := range tltcs { + target, err := table.Lookup(tltc.HostWithPort()) + Expect(err).NotTo(HaveOccurred()) + Expect(target).To(HaveValue(Equal(tltc.Target()))) + } + }) + }) + }) +}) + +type tableLookupTestCase struct { + target Target +} + +func newTableLookupTestCase() tableLookupTestCase { + target := NewTarget( + strconv.Itoa(rand.Int()), + strconv.Itoa(rand.Int()), + rand.Intn(math.MaxUint16), + strconv.Itoa(rand.Int()), + int32(rand.Intn(math.MaxUint8)), + ) + + return tableLookupTestCase{ + target: target, + } +} + +func (tltc tableLookupTestCase) Target() Target { + return tltc.target +} + +func (tltc tableLookupTestCase) HostWithoutPort() string { + return tltc.target.Service + "." + tltc.target.Namespace + ".svc.cluster.local" +} + +func (tltc tableLookupTestCase) HostWithPort() string { + return tltc.HostWithoutPort() + ":" + strconv.Itoa(tltc.target.Port) +} + +type tableLookupTestCases []tableLookupTestCase + +func newTableLookupTestCases(count uint) tableLookupTestCases { + tltcs := make(tableLookupTestCases, count) + for i := uint(0); i < count; i++ { + tltcs[i] = newTableLookupTestCase() + } + return tltcs +}