| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package topologyv1 |
| 4 | |
| 5 | import "fmt" |
| 6 | |
| 7 | const ( |
| 8 | OverlayProviderNetdataMetrics = "netdata.metrics" |
| 9 | OverlayProviderNetdataFunction = "netdata.function" |
| 10 | OverlayProviderExternal = "external" |
| 11 | |
| 12 | OverlayMergeRefsAppend = "append" |
| 13 | OverlayMergeRefsSet = "set" |
| 14 | |
| 15 | OverlayMergeValuesSum = "sum" |
| 16 | OverlayMergeValuesMin = "min" |
| 17 | OverlayMergeValuesMax = "max" |
| 18 | OverlayMergeValuesAvg = "avg" |
| 19 | OverlayMergeValuesLast = "last" |
| 20 | OverlayMergeValuesNone = "none" |
| 21 | |
| 22 | OverlayRefsTemplateColumn = "template" |
| 23 | OverlayRefsActorColumn = "actor" |
| 24 | OverlayRefsLinkColumn = "link" |
| 25 | ) |
| 26 | |
| 27 | type OverlayTemplateOption func(*OverlayTemplate) |
| 28 | |
| 29 | func NewOverlayTemplate(provider string, merge OverlayMerge, opts ...OverlayTemplateOption) OverlayTemplate { |
| 30 | template := OverlayTemplate{ |
| 31 | Provider: provider, |
| 32 | Merge: merge, |
| 33 | } |
| 34 | for _, opt := range opts { |
| 35 | opt(&template) |
| 36 | } |
| 37 | return template |
| 38 | } |
| 39 | |
| 40 | func WithOverlayContexts(contexts ...string) OverlayTemplateOption { |
| 41 | return func(template *OverlayTemplate) { |
| 42 | template.Contexts = append([]string(nil), contexts...) |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | func WithOverlayDimensions(dimensions ...string) OverlayTemplateOption { |
| 47 | return func(template *OverlayTemplate) { |
| 48 | template.Dimensions = append([]string(nil), dimensions...) |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | func WithOverlaySelectorParams(params ...string) OverlayTemplateOption { |
| 53 | return func(template *OverlayTemplate) { |
| 54 | template.SelectorParams = append([]string(nil), params...) |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | func NewOverlayMerge(refs, values string) OverlayMerge { |
| 59 | return OverlayMerge{ |
| 60 | Refs: refs, |
| 61 | Values: values, |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | type OverlayRefsBuilder struct { |
| 66 | strings *StringDictionary |
| 67 | selectorNames []string |
| 68 | builder *TableBuilder |
| 69 | err error |
| 70 | } |
| 71 | |
| 72 | func NewActorOverlayRefsBuilder(strings *StringDictionary, selectorNames ...string) *OverlayRefsBuilder { |
| 73 | return newOverlayRefsBuilder(strings, NewColumn(OverlayRefsActorColumn, "actor_ref", WithRole("reference")), selectorNames...) |
| 74 | } |
| 75 | |
| 76 | func NewLinkOverlayRefsBuilder(strings *StringDictionary, selectorNames ...string) *OverlayRefsBuilder { |
| 77 | return newOverlayRefsBuilder(strings, NewColumn(OverlayRefsLinkColumn, "link_ref", WithRole("reference")), selectorNames...) |
| 78 | } |
| 79 | |
| 80 | func newOverlayRefsBuilder(strings *StringDictionary, ownerColumn Column, selectorNames ...string) *OverlayRefsBuilder { |
| 81 | columns := []Column{ |
| 82 | NewColumn(OverlayRefsTemplateColumn, "string_ref", WithDictionary("strings")), |
| 83 | ownerColumn, |
| 84 | } |
| 85 | for _, name := range selectorNames { |
| 86 | columns = append(columns, NewColumn(name, "string_ref", WithDictionary("strings"))) |
| 87 | } |
| 88 | |
| 89 | return &OverlayRefsBuilder{ |
| 90 | strings: strings, |
| 91 | selectorNames: append([]string(nil), selectorNames...), |
| 92 | builder: NewTableBuilder(columns...), |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | func (b *OverlayRefsBuilder) Add(template string, owner int, selectorValues ...string) int { |
| 97 | row := b.builder.Rows() |
| 98 | if b.err != nil { |
| 99 | return row |
| 100 | } |
| 101 | if b.strings == nil { |
| 102 | b.err = fmt.Errorf("overlay refs builder requires string dictionary") |
| 103 | return row |
| 104 | } |
| 105 | if len(selectorValues) != len(b.selectorNames) { |
| 106 | b.err = fmt.Errorf("overlay ref has %d selector values for %d selector params", len(selectorValues), len(b.selectorNames)) |
| 107 | return row |
| 108 | } |
| 109 | |
| 110 | values := make([]any, 0, len(selectorValues)+2) |
| 111 | values = append(values, b.strings.Ref(template), owner) |
| 112 | for _, value := range selectorValues { |
| 113 | values = append(values, b.strings.Ref(value)) |
| 114 | } |
| 115 | return b.builder.Add(values...) |
| 116 | } |
| 117 | |
| 118 | func (b *OverlayRefsBuilder) Rows() int { |
| 119 | return b.builder.Rows() |
| 120 | } |
| 121 | |
| 122 | func (b *OverlayRefsBuilder) OverlayRefs() (*OverlayRefs, error) { |
| 123 | if b.err != nil { |
| 124 | return nil, b.err |
| 125 | } |
| 126 | if b.Rows() == 0 { |
| 127 | return nil, nil |
| 128 | } |
| 129 | table, err := b.builder.Table() |
| 130 | if err != nil { |
| 131 | return nil, err |
| 132 | } |
| 133 | return &OverlayRefs{Refs: &table}, nil |
| 134 | } |