diff --git a/api/kubernetes/v1alpha1/virtual_env_types.go b/api/kubernetes/v1alpha1/virtual_env_types.go index 023e785..5c77dc0 100644 --- a/api/kubernetes/v1alpha1/virtual_env_types.go +++ b/api/kubernetes/v1alpha1/virtual_env_types.go @@ -123,7 +123,7 @@ type Problem struct { // +kubebuilder:validation:Required // ObservedTime at which the problem was recorded. - ObservedTime api.UncomparableTime `json:"observedTime"` + ObservedTime metav1.Time `json:"observedTime"` Message string `json:"message,omitempty"` // Resources and attributes causing problem. diff --git a/api/types.go b/api/types.go index 3dbfbc9..d1a3c3d 100644 --- a/api/types.go +++ b/api/types.go @@ -9,11 +9,6 @@ one at https://mozilla.org/MPL/2.0/. // +kubebuilder:object:generate=true package api -import ( - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - type VirtualEnvData struct { // +kubebuilder:validation:Schemaless // +kubebuilder:validation:Type=object @@ -70,23 +65,3 @@ type Adapter interface { GetName() string GetComponentType() ComponentType } - -// +kubebuilder:object:generate=false - -// UncomparableTime is a Kubernetes v1.Time object that will also be equal to -// another UncomparableTime object when using equality.Semantic, even if the -// times are different. -type UncomparableTime metav1.Time - -// DeepCopyInto creates a deep-copy of the UncomparableTime value. The -// underlying time.Time type is effectively immutable in the time API, so it is -// safe to copy-by-assign, despite the presence of (unexported) Pointer fields. -func (t *UncomparableTime) DeepCopyInto(out *UncomparableTime) { - *out = *t -} - -func init() { - equality.Semantic.AddFunc(func(a, b UncomparableTime) bool { - return true - }) -} diff --git a/api/types_test.go b/api/types_test.go deleted file mode 100644 index b706139..0000000 --- a/api/types_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright © 2023 XigXog - -This Source Code Form is subject to the terms of the Mozilla Public License, -v2.0. If a copy of the MPL was not distributed with this file, You can obtain -one at https://mozilla.org/MPL/2.0/. -*/ - -// +kubebuilder:object:generate=true -package api - -import ( - "testing" - - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestUncomparableTime(t *testing.T) { - var t1 struct { - T UncomparableTime - } - var t2 struct { - T UncomparableTime - } - t1.T = UncomparableTime(metav1.Now()) - t2.T = UncomparableTime{} - - if !equality.Semantic.DeepEqual(t1, t2) { - t.Fail() - } -} diff --git a/components/broker/engine/broker.go b/components/broker/engine/broker.go index 9f60187..0eabec8 100644 --- a/components/broker/engine/broker.go +++ b/components/broker/engine/broker.go @@ -20,6 +20,7 @@ import ( "github.com/xigxog/kubefox/core" "github.com/xigxog/kubefox/k8s" "github.com/xigxog/kubefox/logkf" + "github.com/xigxog/kubefox/matcher" authv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ctrl "sigs.k8s.io/controller-runtime" @@ -400,7 +401,7 @@ func (brk *broker) findTarget(ctx context.Context, evt *BrokerEvent) error { } var ( - matcher *core.EventMatcher + matcher *matcher.EventMatcher err error ) if evt.HasContext() { diff --git a/components/broker/engine/store.go b/components/broker/engine/store.go index d1be36a..fcc39b2 100644 --- a/components/broker/engine/store.go +++ b/components/broker/engine/store.go @@ -14,6 +14,7 @@ import ( "github.com/xigxog/kubefox/core" "github.com/xigxog/kubefox/k8s" "github.com/xigxog/kubefox/logkf" + "github.com/xigxog/kubefox/matcher" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -29,8 +30,8 @@ type Store struct { resCache ctrlcache.Cache compCache cache.Cache[*api.ComponentDefinition] - depMatchers cache.Cache[*core.EventMatcher] - relMatcher *core.EventMatcher + depMatchers cache.Cache[*matcher.EventMatcher] + relMatcher *matcher.EventMatcher ctx context.Context cancel context.CancelFunc @@ -44,7 +45,7 @@ func NewStore(namespace string) *Store { ctx, cancel := context.WithCancel(context.Background()) return &Store{ namespace: namespace, - depMatchers: cache.New[*core.EventMatcher](time.Minute * 15), + depMatchers: cache.New[*matcher.EventMatcher](time.Minute * 15), ctx: ctx, cancel: cancel, log: logkf.Global, @@ -211,7 +212,7 @@ func (str *Store) Adapters(ctx context.Context) (map[string]api.Adapter, error) return adapters, nil } -func (str *Store) ReleaseMatcher(ctx context.Context) (*core.EventMatcher, error) { +func (str *Store) ReleaseMatcher(ctx context.Context) (*matcher.EventMatcher, error) { str.mutex.RLock() if str.relMatcher != nil { str.mutex.RUnlock() @@ -225,7 +226,7 @@ func (str *Store) ReleaseMatcher(ctx context.Context) (*core.EventMatcher, error return str.relMatcher, nil } -func (str *Store) DeploymentMatcher(ctx context.Context, evtCtx *core.EventContext) (*core.EventMatcher, error) { +func (str *Store) DeploymentMatcher(ctx context.Context, evtCtx *core.EventContext) (*matcher.EventMatcher, error) { dep, err := str.AppDeployment(ctx, evtCtx) if err != nil { return nil, err @@ -245,7 +246,7 @@ func (str *Store) DeploymentMatcher(ctx context.Context, evtCtx *core.EventConte return nil, err } - depM := core.NewEventMatcher() + depM := matcher.New() if err := depM.AddRoutes(routes...); err != nil { return nil, err } @@ -333,7 +334,7 @@ func (str *Store) buildComponentCache(ctx context.Context) (cache.Cache[*api.Com return compCache, nil } -func (str *Store) buildReleaseMatcher(ctx context.Context) (*core.EventMatcher, error) { +func (str *Store) buildReleaseMatcher(ctx context.Context) (*matcher.EventMatcher, error) { ctx, cancel := context.WithTimeout(ctx, time.Minute) defer cancel() @@ -342,7 +343,7 @@ func (str *Store) buildReleaseMatcher(ctx context.Context) (*core.EventMatcher, return nil, err } - relM := core.NewEventMatcher() + relM := matcher.New() for _, env := range envList.Items { release := env.Status.ActiveRelease if release == nil { diff --git a/components/operator/controller/virtual_env_controller.go b/components/operator/controller/virtual_env_controller.go index 56ad36a..37d703b 100644 --- a/components/operator/controller/virtual_env_controller.go +++ b/components/operator/controller/virtual_env_controller.go @@ -294,7 +294,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti value := string(metav1.ConditionFalse) rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypeAppDeploymentUnavailable, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -316,7 +316,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti value := fmt.Sprintf("%s, %s", metav1.ConditionFalse, api.ConditionReasonComponentDeploymentFailed) rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypeAppDeploymentFailed, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -337,7 +337,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypeAppDeploymentFailed, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -363,7 +363,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypeAppDeploymentFailed, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -389,7 +389,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypeVirtualEnvSnapshotFailed, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -410,7 +410,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypeVirtualEnvSnapshotFailed, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -438,7 +438,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti value := string(policy.VirtualEnvPolicy) rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypePolicyViolation, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { @@ -462,7 +462,7 @@ func (r *VirtualEnvReconciler) updateProblems(ctx context.Context, now metav1.Ti value := string(policy.AppDeploymentPolicy) rel.Problems = append(rel.Problems, v1alpha1.Problem{ Type: api.ProblemTypePolicyViolation, - ObservedTime: api.UncomparableTime(now), + ObservedTime: now, Message: msg, Causes: []v1alpha1.ProblemSource{ { diff --git a/docs/reference/kubernetes-crds.md b/docs/reference/kubernetes-crds.md index 875f4ef..7328041 100644 --- a/docs/reference/kubernetes-crds.md +++ b/docs/reference/kubernetes-crds.md @@ -114,7 +114,6 @@ Platform is the Schema for the Platforms API - ### VirtualEnv @@ -641,7 +640,7 @@ Used by:
| Field | Type | Description | Validation | | ----- | ---- | ----------- | ---------- | | `type` |
enum[`AppDeploymentFailed`, `AppDeploymentUnavailable`, `ParseError`, `PolicyViolation`, `RouteConflict`, `SecretNotFound`, `VarNotFound`, `VarWrongType`, `VirtualEnvSnapshotFailed`]
|
|
required
| -| `observedTime` |
[UncomparableTime](#uncomparabletime)
|
ObservedTime at which the problem was recorded.
|
required
| +| `observedTime` |
[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#time-v1-meta)
|
ObservedTime at which the problem was recorded.
|
required
| | `message` |
string
|
|
| | `causes` |
[ProblemSource](#problemsource) array
|
Resources and attributes causing problem.
|
| @@ -805,9 +804,6 @@ Used by:
- - - ### Val diff --git a/core/event_matcher.go b/matcher/event_matcher.go similarity index 90% rename from core/event_matcher.go rename to matcher/event_matcher.go index 94fee1f..6b9f377 100644 --- a/core/event_matcher.go +++ b/matcher/event_matcher.go @@ -1,4 +1,4 @@ -package core +package matcher import ( "fmt" @@ -9,10 +9,11 @@ import ( "github.com/vulcand/predicate" "github.com/xigxog/kubefox/api" + "github.com/xigxog/kubefox/core" ) // Takes an Event and returns true or false if rule matches. -type EventPredicate func(e *Event) bool +type EventPredicate func(e *core.Event) bool type param struct { name string @@ -20,7 +21,7 @@ type param struct { } type parsedRoute struct { - *Route + *core.Route predicate EventPredicate } @@ -30,7 +31,7 @@ type EventMatcher struct { parser predicate.Parser } -func NewEventMatcher() *EventMatcher { +func New() *EventMatcher { m := &EventMatcher{} // TODO add various event criteria for route predicates: @@ -61,7 +62,7 @@ func NewEventMatcher() *EventMatcher { return m } -func (m *EventMatcher) AddRoutes(routes ...*Route) error { +func (m *EventMatcher) AddRoutes(routes ...*core.Route) error { for _, r := range routes { if r.ResolvedRule == "" { return fmt.Errorf("rule '%d' has not been resolved", r.Id()) @@ -86,7 +87,7 @@ func (m *EventMatcher) AddRoutes(routes ...*Route) error { return nil } -func (m *EventMatcher) Match(evt *Event) (*Route, bool) { +func (m *EventMatcher) Match(evt *core.Event) (*core.Route, bool) { for _, r := range m.rules { if r.predicate(evt) { return r.Route, true @@ -97,7 +98,7 @@ func (m *EventMatcher) Match(evt *Event) (*Route, bool) { } func (m *EventMatcher) all() EventPredicate { - return func(e *Event) bool { + return func(e *core.Event) bool { return true } } @@ -113,7 +114,7 @@ func (m *EventMatcher) header(key, val string) (EventPredicate, error) { return nil, fmt.Errorf("invalid regex of header predicate %s: %w", val, err) } - return func(e *Event) bool { + return func(e *core.Event) bool { return matchMap(key, val, regex, e.ValueMap(api.ValKeyHeader)) }, nil } @@ -124,13 +125,13 @@ func (m *EventMatcher) host(s string) (EventPredicate, error) { return nil, err } - return func(e *Event) bool { + return func(e *core.Event) bool { return matchParts(api.ValKeyHost, ".", parts, params, e, false) }, nil } func (m *EventMatcher) method(s ...string) EventPredicate { - return func(e *Event) bool { + return func(e *core.Event) bool { m := e.Value(api.ValKeyMethod) for _, v := range s { if strings.EqualFold(m, v) { @@ -147,7 +148,7 @@ func (m *EventMatcher) path(s string) (EventPredicate, error) { return nil, err } - return func(e *Event) bool { + return func(e *core.Event) bool { return matchParts(api.ValKeyPath, "/", parts, params, e, false) }, nil } @@ -158,7 +159,7 @@ func (m *EventMatcher) pathPrefix(s string) (EventPredicate, error) { return nil, err } - return func(e *Event) bool { + return func(e *core.Event) bool { return matchParts(api.ValKeyPath, "/", parts, params, e, true) }, nil } @@ -173,13 +174,13 @@ func (m *EventMatcher) query(key, val string) (EventPredicate, error) { return nil, fmt.Errorf("invalid regex of query predicate %s: %w", val, err) } - return func(e *Event) bool { + return func(e *core.Event) bool { return matchMap(key, val, regex, e.ValueMap(api.ValKeyQuery)) }, nil } func (m *EventMatcher) eventType(s string) EventPredicate { - return func(e *Event) bool { + return func(e *core.Event) bool { return e.GetType() == s || strings.HasSuffix(strings.ToLower(e.GetType()), strings.ToLower(s)) } @@ -187,21 +188,21 @@ func (m *EventMatcher) eventType(s string) EventPredicate { // Logical operator AND that combines predicates func and(a, b EventPredicate) EventPredicate { - return func(e *Event) bool { + return func(e *core.Event) bool { return a(e) && b(e) } } // Logical operator OR that combines predicates func or(a, b EventPredicate) EventPredicate { - return func(e *Event) bool { + return func(e *core.Event) bool { return a(e) || b(e) } } // Logical operator NOT that negates predicates func not(a EventPredicate) EventPredicate { - return func(e *Event) bool { + return func(e *core.Event) bool { return !a(e) } } @@ -236,7 +237,7 @@ func matchMap(key, val string, regex *regexp.Regexp, m map[string][]string) bool return false } -func matchParts(val string, sep string, parts []string, params map[int]*param, e *Event, prefix bool) bool { +func matchParts(val string, sep string, parts []string, params map[int]*param, e *core.Event, prefix bool) bool { evtParts := strings.Split(strings.Trim(e.Value(val), sep), sep) if len(parts) > len(evtParts) { diff --git a/core/event_matcher_test.go b/matcher/event_matcher_test.go similarity index 68% rename from core/event_matcher_test.go rename to matcher/event_matcher_test.go index 7d59304..5f4c015 100644 --- a/core/event_matcher_test.go +++ b/matcher/event_matcher_test.go @@ -1,9 +1,10 @@ -package core +package matcher import ( "testing" "github.com/xigxog/kubefox/api" + "github.com/xigxog/kubefox/core" ) func TestPath(t *testing.T) { @@ -15,15 +16,15 @@ func TestPath(t *testing.T) { }, } - rule1, _ := NewRule(1, "PathPrefix(`/customize/{{.Vars.b}}`)") - route1 := &Route{Rule: rule1} + rule1, _ := core.NewRule(1, "PathPrefix(`/customize/{{.Vars.b}}`)") + route1 := &core.Route{Rule: rule1} route1.Resolve(data) - rule2, _ := NewRule(2, "Type(`http`) && Method(`PUT`,`GET`,`POST`) && (Query(`q1`, `{q[1-2]}`) && Header(`header-one`,`{[a-z0-9]+}`)) && Host(`{{.Env.a}}.0.0.{i}`) && Path(`/customize/{{.Vars.b}}/{j:[a-z]+}`)") - route2 := &Route{Rule: rule2} + rule2, _ := core.NewRule(2, "Type(`http`) && Method(`PUT`,`GET`,`POST`) && (Query(`q1`, `{q[1-2]}`) && Header(`header-one`,`{[a-z0-9]+}`)) && Host(`{{.Env.a}}.0.0.{i}`) && Path(`/customize/{{.Vars.b}}/{j:[a-z]+}`)") + route2 := &core.Route{Rule: rule2} route2.Resolve(data) - m := NewEventMatcher() + m := New() m.AddRoutes(route1, route2) e := evt(api.EventTypeHTTP) @@ -41,8 +42,8 @@ func TestPath(t *testing.T) { t.Logf("matched route %d; i=%s, j=%s", r.Id(), e.Param("i"), e.Param("j")) } -func evt(evtType api.EventType) *Event { - evt := NewEvent() +func evt(evtType api.EventType) *core.Event { + evt := core.NewEvent() evt.Type = string(evtType) evt.SetValue(api.ValKeyURL, "http://127.0.0.1/customize/1/a?q1=q1&q2=q2") evt.SetValue(api.ValKeyHost, "127.0.0.1")