Skip to content

Commit 0ae8448

Browse files
committed
add missing file
1 parent 6694dcb commit 0ae8448

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

pkg/snclient/inventory.go

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package snclient
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"runtime"
7+
"slices"
8+
"sort"
9+
"strings"
10+
"sync"
11+
"time"
12+
)
13+
14+
const (
15+
// InventoryCacheDuration sets the cache duration for inventory.
16+
InventoryCacheDuration = 10 * time.Second
17+
)
18+
19+
type Inventory map[string]interface{}
20+
21+
type InvCache struct {
22+
mutex sync.Mutex
23+
cond *sync.Cond
24+
inventory *Inventory
25+
lastUpdate time.Time
26+
updating bool
27+
}
28+
29+
func NewInvCache() *InvCache {
30+
c := &InvCache{}
31+
c.cond = sync.NewCond(&c.mutex)
32+
33+
return c
34+
}
35+
36+
func (ic *InvCache) Get(ctx context.Context, snc *Agent) *Inventory {
37+
ic.mutex.Lock()
38+
defer ic.mutex.Unlock()
39+
40+
// if fresh, return immediately
41+
if ic.inventory != nil && time.Since(ic.lastUpdate) < InventoryCacheDuration {
42+
return ic.inventory
43+
}
44+
45+
// if another goroutine is already updating, wait
46+
if ic.updating {
47+
for ic.updating {
48+
ic.cond.Wait()
49+
}
50+
51+
return ic.inventory
52+
}
53+
54+
// run the update
55+
ic.updating = true
56+
ic.mutex.Unlock()
57+
58+
// do the update outside of lock
59+
newInv := snc.buildInventory(ctx, nil)
60+
61+
ic.mutex.Lock()
62+
defer ic.cond.Broadcast() // wake all waiting goroutines
63+
ic.updating = false
64+
65+
ic.inventory = newInv
66+
ic.lastUpdate = time.Now()
67+
68+
return ic.inventory
69+
}
70+
71+
func (snc *Agent) getInventoryEntry(ctx context.Context, checkName string) (listData []map[string]string, err error) {
72+
checkName = strings.TrimPrefix(checkName, "check_")
73+
rawInv := snc.GetInventory(ctx, []string{checkName})
74+
invInterface, ok := rawInv["inventory"]
75+
if !ok {
76+
return nil, fmt.Errorf("check %s not found in inventory", checkName)
77+
}
78+
79+
inv, ok := invInterface.(*Inventory)
80+
if !ok {
81+
return nil, fmt.Errorf("unexpected inventory type: %T", inv)
82+
}
83+
84+
list, ok := (*inv)[checkName]
85+
if !ok {
86+
return nil, fmt.Errorf("unexpected inventory entry type: %T", list)
87+
}
88+
89+
data, ok := list.([]map[string]string)
90+
if !ok {
91+
return nil, fmt.Errorf("could not build inventory for %s", checkName)
92+
}
93+
94+
return data, nil
95+
}
96+
97+
func (snc *Agent) buildInventory(ctx context.Context, modules []string) *Inventory {
98+
scripts := make([]string, 0)
99+
inventory := make(Inventory)
100+
101+
keys := make([]string, 0)
102+
for k := range AvailableChecks {
103+
keys = append(keys, k)
104+
}
105+
for k := range snc.runSet.cmdAliases {
106+
keys = append(keys, k)
107+
}
108+
for k := range snc.runSet.cmdWraps {
109+
keys = append(keys, k)
110+
}
111+
sort.Strings(keys)
112+
113+
for _, k := range keys {
114+
check, _ := snc.getCheck(k)
115+
handler := check.Handler()
116+
meta := handler.Build()
117+
if !meta.isImplemented(runtime.GOOS) {
118+
log.Debugf("skipping inventory for unimplemented (%s) check: %s / %s", runtime.GOOS, k, check.Name)
119+
120+
continue
121+
}
122+
switch meta.hasInventory {
123+
case NoInventory:
124+
// skipped
125+
case ListInventory:
126+
name := strings.TrimPrefix(check.Name, "check_")
127+
if len(modules) > 0 && (!slices.Contains(modules, name)) {
128+
continue
129+
}
130+
meta.output = "inventory_json"
131+
meta.filter = ConditionList{{isNone: true}}
132+
data, err := handler.Check(ctx, snc, meta, []Argument{})
133+
if err != nil && (data == nil || data.Raw == nil) {
134+
log.Tracef("inventory %s returned error: %s", check.Name, err.Error())
135+
136+
continue
137+
}
138+
139+
inventory[name] = data.Raw.listData
140+
case NoCallInventory:
141+
name := strings.TrimPrefix(check.Name, "check_")
142+
if len(modules) > 0 && !slices.Contains(modules, name) {
143+
continue
144+
}
145+
inventory[name] = []interface{}{}
146+
case ScriptsInventory:
147+
scripts = append(scripts, check.Name)
148+
}
149+
}
150+
151+
if len(modules) == 0 || slices.Contains(modules, "scripts") {
152+
inventory["scripts"] = scripts
153+
}
154+
155+
if len(modules) == 0 || slices.Contains(modules, "exporter") {
156+
inventory["exporter"] = snc.listExporter()
157+
}
158+
159+
return &inventory
160+
}

0 commit comments

Comments
 (0)