Skip to content

Commit

Permalink
feat: improve kubernetes relationship selector and use the db methods
Browse files Browse the repository at this point in the history
from duty
  • Loading branch information
adityathebe authored and moshloop committed Feb 1, 2024
1 parent 277d2f5 commit 6cdadbf
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 209 deletions.
85 changes: 41 additions & 44 deletions api/v1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ import (
"fmt"
"net/url"
"regexp"
"sort"
"strings"

"github.com/flanksource/commons/hash"
"github.com/flanksource/duty/models"
"github.com/flanksource/duty/types"
"github.com/flanksource/gomplate/v3"
"github.com/samber/lo"
)

// ConfigFieldExclusion defines fields with JSONPath that needs to
Expand Down Expand Up @@ -132,44 +129,36 @@ func (t *RelationshipLookup) Eval(labels map[string]string, envVar map[string]an
}

func (t RelationshipLookup) IsEmpty() bool {
if t.Value == "" && t.Label == "" && t.Expr == "" {
return true
}

return false
return t.Value == "" && t.Label == "" && t.Expr == ""
}

// RelationshipSelector is the evaluated output of RelationshipSelector.
//
// NOTE: The fields are pointers because we need to differentiate between
// empty filter (null value) and empty result (output of the filter).
type RelationshipSelector struct {
ID *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
Type *string `json:"type,omitempty"`
Agent *string `json:"agent,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Agent string `json:"agent,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}

func (t *RelationshipSelector) Hash() string {
items := []string{
lo.FromPtr(t.ID),
lo.FromPtr(t.Name),
lo.FromPtr(t.Type),
lo.FromPtr(t.Agent),
}

labelkeys := lo.Keys(t.Labels)
sort.Slice(labelkeys, func(i, j int) bool { return labelkeys[i] < labelkeys[j] })
for _, k := range labelkeys {
items = append(items, fmt.Sprintf("%s=%s", k, t.Labels[k]))
}

return hash.Sha256Hex(strings.Join(items, "|"))
func (t *RelationshipSelector) IsEmpty() bool {
return t.ID == "" && t.Name == "" && t.Type == "" && t.Agent == "" && len(t.Labels) == 0
}

func (t *RelationshipSelector) IsEmpty() bool {
return t.ID == nil && t.Name == nil && t.Type == nil && t.Agent == nil && len(t.Labels) == 0
func (t *RelationshipSelector) ToResourceSelector() types.ResourceSelector {
var labelSelector string
for k, v := range t.Labels {
labelSelector += fmt.Sprintf("%s=%s,", k, v)
}
labelSelector = strings.TrimSuffix(labelSelector, ",")

return types.ResourceSelector{
ID: t.ID,
Name: t.Name,
Types: []string{t.Type},
Agent: t.Agent,
LabelSelector: labelSelector,
}
}

type RelationshipSelectorTemplate struct {
Expand All @@ -188,38 +177,46 @@ func (t *RelationshipSelectorTemplate) IsEmpty() bool {
return t.ID.IsEmpty() && t.Name.IsEmpty() && t.Type.IsEmpty() && t.Agent.IsEmpty() && len(t.Labels) == 0
}

// Eval evaluates the template and returns a RelationshipSelector.
// If any of the filter returns an empty value, the evaluation results to a nil selector.
// i.e. if a lookup is non-empty, it must return a non-empty value.
func (t *RelationshipSelectorTemplate) Eval(labels map[string]string, env map[string]any) (*RelationshipSelector, error) {
if t.IsEmpty() {
return nil, nil
}

var output RelationshipSelector
var err error

if !t.ID.IsEmpty() {
if res, err := t.ID.Eval(labels, env); err != nil {
if output.ID, err = t.ID.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate id: %v for config relationship: %w", t.ID, err)
} else {
output.ID = &res
} else if output.ID == "" {
return nil, nil
}
}

if !t.Name.IsEmpty() {
if res, err := t.Name.Eval(labels, env); err != nil {
if output.Name, err = t.Name.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate name: %v for config relationship: %w", t.Name, err)
} else {
output.Name = &res
} else if output.Name == "" {
return nil, nil
}
}

if !t.Type.IsEmpty() {
if res, err := t.Type.Eval(labels, env); err != nil {
if output.Type, err = t.Type.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate type: %v for config relationship: %w", t.Type, err)
} else {
output.Type = &res
} else if output.Type == "" {
return nil, nil
}
}

if !t.Agent.IsEmpty() {
if res, err := t.Agent.Eval(labels, env); err != nil {
if output.Agent, err = t.Agent.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate agent_id: %v for config relationship: %w", t.Agent, err)
} else {
output.Agent = &res
} else if output.Agent == "" {
return nil, nil
}
}

Expand Down
52 changes: 50 additions & 2 deletions api/v1/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,13 @@ func (t *KubernetesExclusionConfig) Filter(name, namespace, kind string, labels
return false
}

type KubernetesRelationship struct {
type KubernetesRelationshipSelector struct {
Kind string `json:"kind" yaml:"kind"`
Name string `json:"name" yaml:"name"`
Namespace string `json:"namespace" yaml:"namespace"`
}

type KubernetesRelationshipSelectorTemplate struct {
// Kind defines which field to use for the kind lookup
Kind RelationshipLookup `json:"kind" yaml:"kind"`
// Name defines which field to use for the name lookup
Expand All @@ -112,6 +118,48 @@ type KubernetesRelationship struct {
Namespace RelationshipLookup `json:"namespace" yaml:"namespace"`
}

func (t *KubernetesRelationshipSelectorTemplate) IsEmpty() bool {
return t.Kind.IsEmpty() && t.Name.IsEmpty() && t.Namespace.IsEmpty()
}

// Eval evaluates the template and returns a KubernetesRelationshipSelector.
// If any of the filter returns an empty value, the evaluation results to a nil selector.
// i.e. if a lookup is non-empty, it must return a non-empty value.
func (t *KubernetesRelationshipSelectorTemplate) Eval(labels map[string]string, env map[string]any) (*KubernetesRelationshipSelector, error) {
if t.IsEmpty() {
return nil, nil
}

var output KubernetesRelationshipSelector
var err error

if !t.Name.IsEmpty() {
if output.Name, err = t.Name.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate Name: %s: %w", t.Name, err)
} else if output.Name == "" {
return nil, nil
}
}

if !t.Kind.IsEmpty() {
if output.Kind, err = t.Kind.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate kind: %s: %w", t.Kind, err)
} else if output.Kind == "" {
return nil, nil
}
}

if !t.Namespace.IsEmpty() {
if output.Namespace, err = t.Namespace.Eval(labels, env); err != nil {
return nil, fmt.Errorf("failed to evaluate namespace: %s: %w", t.Namespace, err)
} else if output.Namespace == "" {
return nil, nil
}
}

return &output, nil
}

type Kubernetes struct {
BaseScraper `json:",inline"`
ClusterName string `json:"clusterName,omitempty"`
Expand All @@ -128,7 +176,7 @@ type Kubernetes struct {
Event KubernetesEventConfig `json:"event,omitempty"`

// Relationships specify the fields to use to relate Kubernetes objects.
Relationships []KubernetesRelationship `json:"relationships,omitempty"`
Relationships []KubernetesRelationshipSelectorTemplate `json:"relationships,omitempty"`
}

type KubernetesFile struct {
Expand Down
45 changes: 20 additions & 25 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions cmd/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ func run(cmd *cobra.Command, args []string) {
loggr := ctrlzap.NewRaw(
ctrlzap.UseDevMode(true),
ctrlzap.WriteTo(os.Stderr),
ctrlzap.Level(zapLogger.Level),
ctrlzap.StacktraceLevel(zapLogger.StackTraceLevel),
ctrlzap.Encoder(zapLogger.GetEncoder()),
// FIXME: Breaking after duty bump.
// ctrlzap.Level(zapLogger.Level),
// ctrlzap.StacktraceLevel(zapLogger.StackTraceLevel),
// ctrlzap.Encoder(zapLogger.GetEncoder()),
)

ctrl.SetLogger(zapr.NewLogger(loggr))
Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var Root = &cobra.Command{
count, _ := cmd.Flags().GetCount("loglevel")
// logger.StandardLogger().(logsrusapi.Logger).Out = os.Stderr
logger.StandardLogger().SetLogLevel(count)
logger.UseZap(cmd.Flags())
logger.UseZap()
var err error

if api.KubernetesClient, api.KubernetesRestConfig, err = kube.NewK8sClient(); err != nil {
Expand Down
Loading

0 comments on commit 6cdadbf

Please sign in to comment.