generated from kedacore/github-template
-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Erich Shan
committed
Dec 22, 2024
1 parent
94bf27f
commit b1b19ad
Showing
9 changed files
with
378 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package routing | ||
|
||
import ( | ||
iradix "github.com/hashicorp/go-immutable-radix/v2" | ||
httpv1alpha1 "github.com/kedacore/http-add-on/operator/apis/http/v1alpha1" | ||
) | ||
|
||
type httpSOIndex struct { | ||
radix *iradix.Tree[*httpv1alpha1.HTTPScaledObject] | ||
} | ||
|
||
func newHTTPSOIndex() *httpSOIndex { | ||
return &httpSOIndex{radix: iradix.New[*httpv1alpha1.HTTPScaledObject]()} | ||
} | ||
|
||
func (hi *httpSOIndex) insert(key tableMemoryIndexKey, httpso *httpv1alpha1.HTTPScaledObject) (*httpSOIndex, *httpv1alpha1.HTTPScaledObject, bool) { | ||
newRadix, oldVal, ok := hi.radix.Insert(key, httpso) | ||
newHttpSOIndex := &httpSOIndex{ | ||
radix: newRadix, | ||
} | ||
return newHttpSOIndex, oldVal, ok | ||
} | ||
|
||
func (hi *httpSOIndex) get(key tableMemoryIndexKey) (*httpv1alpha1.HTTPScaledObject, bool) { | ||
return hi.radix.Get(key) | ||
} | ||
|
||
func (hi *httpSOIndex) delete(key tableMemoryIndexKey) (*httpSOIndex, *httpv1alpha1.HTTPScaledObject) { | ||
newRadix, oldHttpSO, _ := hi.radix.Delete(key) | ||
newHttpSOIndex := &httpSOIndex{ | ||
radix: newRadix, | ||
} | ||
return newHttpSOIndex, oldHttpSO | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package routing | ||
|
||
import ( | ||
httpv1alpha1 "github.com/kedacore/http-add-on/operator/apis/http/v1alpha1" | ||
"github.com/kedacore/http-add-on/pkg/k8s" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
var _ = Describe("httpSOIndex", func() { | ||
var ( | ||
httpso0 = &httpv1alpha1.HTTPScaledObject{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "keda-sh", | ||
}, | ||
Spec: httpv1alpha1.HTTPScaledObjectSpec{ | ||
Hosts: []string{ | ||
"keda.sh", | ||
}, | ||
}, | ||
} | ||
|
||
httpso0NamespacedName = k8s.NamespacedNameFromObject(httpso0) | ||
httpso0IndexKey = newTableMemoryIndexKey(httpso0NamespacedName) | ||
|
||
httpso1 = &httpv1alpha1.HTTPScaledObject{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "one-one-one-one", | ||
}, | ||
Spec: httpv1alpha1.HTTPScaledObjectSpec{ | ||
Hosts: []string{ | ||
"1.1.1.1", | ||
}, | ||
}, | ||
} | ||
httpso1NamespacedName = k8s.NamespacedNameFromObject(httpso1) | ||
httpso1IndexKey = newTableMemoryIndexKey(httpso1NamespacedName) | ||
) | ||
Context("New", func() { | ||
It("returns a httpSOIndex with initialized tree", func() { | ||
index := newHTTPSOIndex() | ||
Expect(index.radix).NotTo(BeNil()) | ||
}) | ||
}) | ||
|
||
Context("Get / Insert", func() { | ||
It("Get on empty httpSOIndex returns nil", func() { | ||
index := newHTTPSOIndex() | ||
_, ok := index.get(httpso0IndexKey) | ||
Expect(ok).To(BeFalse()) | ||
}) | ||
It("httpSOIndex insert will return previous object if set", func() { | ||
index := newHTTPSOIndex() | ||
index, prevVal, prevSet := index.insert(httpso0IndexKey, httpso0) | ||
Expect(prevSet).To(BeFalse()) | ||
Expect(prevVal).To(BeNil()) | ||
httpso0Copy := httpso0.DeepCopy() | ||
httpso0Copy.Name = "httpso0Copy" | ||
index, prevVal, prevSet = index.insert(httpso0IndexKey, httpso0Copy) | ||
Expect(prevSet).To(BeTrue()) | ||
Expect(prevVal).To(Equal(httpso0)) | ||
Expect(prevVal).ToNot(Equal(httpso0Copy)) | ||
httpso, ok := index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).ToNot(Equal(httpso0)) | ||
Expect(httpso).To(Equal(httpso0Copy)) | ||
}) | ||
|
||
It("httpSOIndex with new object inserted returns object", func() { | ||
index := newHTTPSOIndex() | ||
index, httpso, prevSet := index.insert(httpso0IndexKey, httpso0) | ||
Expect(prevSet).To(BeFalse()) | ||
Expect(httpso).To(BeNil()) | ||
httpso, ok := index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso0)) | ||
}) | ||
|
||
It("httpSOIndex with new object inserted retains other object", func() { | ||
index := newHTTPSOIndex() | ||
|
||
index, _, _ = index.insert(httpso0IndexKey, httpso0) | ||
httpso, ok := index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso0)) | ||
|
||
_, ok = index.get(httpso1IndexKey) | ||
Expect(ok).To(BeFalse()) | ||
|
||
index, _, _ = index.insert(httpso1IndexKey, httpso1) | ||
httpso, ok = index.get(httpso1IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso1)) | ||
|
||
// httpso0 still there | ||
httpso, ok = index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso0)) | ||
}) | ||
}) | ||
|
||
Context("Get / Delete", func() { | ||
It("delete on empty httpSOIndex returns nil", func() { | ||
index := newHTTPSOIndex() | ||
_, httpso := index.delete(httpso0IndexKey) | ||
Expect(httpso).To(BeNil()) | ||
}) | ||
|
||
It("double delete returns nil the second time", func() { | ||
index := newHTTPSOIndex() | ||
index, _, _ = index.insert(httpso0IndexKey, httpso0) | ||
index, _, _ = index.insert(httpso1IndexKey, httpso1) | ||
index, deletedVal := index.delete(httpso0IndexKey) | ||
Expect(deletedVal).To(Equal(httpso0)) | ||
index, deletedVal = index.delete(httpso0IndexKey) | ||
Expect(deletedVal).To(BeNil()) | ||
}) | ||
|
||
It("delete on httpSOIndex removes object ", func() { | ||
index := newHTTPSOIndex() | ||
index, _, _ = index.insert(httpso0IndexKey, httpso0) | ||
httpso, ok := index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso0)) | ||
index, deletedVal := index.delete(httpso0IndexKey) | ||
Expect(deletedVal).To(Equal(httpso0)) | ||
httpso, ok = index.get(httpso0IndexKey) | ||
Expect(httpso).To(BeNil()) | ||
Expect(ok).To(BeFalse()) | ||
}) | ||
It("httpSOIndex delete on one object does not affect other", func() { | ||
index := newHTTPSOIndex() | ||
|
||
index, _, _ = index.insert(httpso0IndexKey, httpso0) | ||
index, _, _ = index.insert(httpso1IndexKey, httpso1) | ||
httpso, ok := index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso0)) | ||
index, deletedVal := index.delete(httpso1IndexKey) | ||
Expect(deletedVal).To(Equal(httpso1)) | ||
httpso, ok = index.get(httpso0IndexKey) | ||
Expect(ok).To(BeTrue()) | ||
Expect(httpso).To(Equal(httpso0)) | ||
httpso, ok = index.get(httpso1IndexKey) | ||
Expect(ok).To(BeFalse()) | ||
Expect(httpso).To(BeNil()) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package routing | ||
|
||
import ( | ||
iradix "github.com/hashicorp/go-immutable-radix/v2" | ||
httpv1alpha1 "github.com/kedacore/http-add-on/operator/apis/http/v1alpha1" | ||
"github.com/kedacore/http-add-on/pkg/k8s" | ||
) | ||
|
||
// light wrapper around radix tree containing HTTPScaledObjectList | ||
// with convenience functions to manage CRUD for individual HTTPScaledObject. | ||
// created as an abstraction to manage complexity for tablememory implementation | ||
// the store is meant to map host + path keys to one or more HTTPScaledObject | ||
// and return one arbitrarily or route based on headers | ||
type httpSOStore struct { | ||
radix *iradix.Tree[*httpv1alpha1.HTTPScaledObjectList] | ||
} | ||
|
||
func newHTTPSOStore() *httpSOStore { | ||
return &httpSOStore{radix: iradix.New[*httpv1alpha1.HTTPScaledObjectList]()} | ||
} | ||
|
||
// Insert key value into httpSOStore | ||
// Gets old list of HTTPScaledObjectList | ||
// if exists appends to list and returns new httpSOStore | ||
// with new radix tree | ||
func (hs *httpSOStore) append(key Key, httpso *httpv1alpha1.HTTPScaledObject) *httpSOStore { | ||
httpsoList, found := hs.radix.Get(key) | ||
var newHttpSOStore *httpSOStore | ||
if !found { | ||
newList := &httpv1alpha1.HTTPScaledObjectList{Items: []*httpv1alpha1.HTTPScaledObject{httpso}} | ||
newRadix, _, _ := hs.radix.Insert(key, newList) | ||
newHttpSOStore = &httpSOStore{ | ||
radix: newRadix, | ||
} | ||
} else { | ||
newList := &httpv1alpha1.HTTPScaledObjectList{Items: append(httpsoList.Items, httpso)} | ||
newRadix, _, _ := hs.radix.Insert(key, newList) | ||
newHttpSOStore = &httpSOStore{ | ||
radix: newRadix, | ||
} | ||
} | ||
return newHttpSOStore | ||
} | ||
|
||
func (hs *httpSOStore) insert(key Key, httpsoList *httpv1alpha1.HTTPScaledObjectList) (*httpSOStore, *httpv1alpha1.HTTPScaledObjectList, bool) { | ||
newRadix, oldVal, ok := hs.radix.Insert(key, httpsoList) | ||
newHttpSOStore := &httpSOStore{ | ||
radix: newRadix, | ||
} | ||
return newHttpSOStore, oldVal, ok | ||
} | ||
|
||
func (hs *httpSOStore) get(key Key) (*httpv1alpha1.HTTPScaledObjectList, bool) { | ||
return hs.radix.Get(key) | ||
} | ||
|
||
func (hs *httpSOStore) delete(key Key) *httpSOStore { | ||
newRadix, _, _ := hs.radix.Delete(key) | ||
newHttpSOStore := &httpSOStore{ | ||
radix: newRadix, | ||
} | ||
return newHttpSOStore | ||
} | ||
|
||
// convenience function | ||
// retrieves all keys associated with HTTPScaledObject | ||
// and deletes it from every list in the store | ||
func (hs *httpSOStore) DeleteAllInstancesOfHTTPSO(httpso *httpv1alpha1.HTTPScaledObject) *httpSOStore { | ||
httpsoNamespacedName := k8s.NamespacedNameFromObject(httpso) | ||
newHttpSOStore := &httpSOStore{radix: hs.radix} | ||
keys := NewKeysFromHTTPSO(httpso) | ||
for _, key := range keys { | ||
httpsoList, _ := newHttpSOStore.radix.Get(key) | ||
for i, httpso := range httpsoList.Items { | ||
// delete only if namespaced names match | ||
if currHttpsoNamespacedName := k8s.NamespacedNameFromObject(httpso); *httpsoNamespacedName == *currHttpsoNamespacedName { | ||
httpsoList.Items = append(httpsoList.Items[:i], httpsoList.Items[i+1:]...) | ||
break | ||
} | ||
} | ||
if len(httpsoList.Items) == 0 { | ||
newHttpSOStore.radix, _, _ = newHttpSOStore.radix.Delete(key) | ||
} else { | ||
newHttpSOStore.radix, _, _ = newHttpSOStore.radix.Insert(key, httpsoList) | ||
} | ||
} | ||
return newHttpSOStore | ||
} | ||
|
||
func (hs *httpSOStore) GetLongestPrefix(key Key) ([]byte, *httpv1alpha1.HTTPScaledObjectList, bool) { | ||
return hs.radix.Root().LongestPrefix(key) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.