feat: agent metadata with custom collectors
This commit is contained in:
12
internal/agent/metadata/collector.go
Normal file
12
internal/agent/metadata/collector.go
Normal file
@ -0,0 +1,12 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrMetadataNotAvailable = errors.New("metadata not available")
|
||||
|
||||
type Collector interface {
|
||||
Collect(context.Context) (string, string, error)
|
||||
}
|
31
internal/agent/metadata/collector/buildinfo/collector.go
Normal file
31
internal/agent/metadata/collector/buildinfo/collector.go
Normal file
@ -0,0 +1,31 @@
|
||||
package buildinfo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime/debug"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
MetadataBuildInfo = "buildinfo"
|
||||
)
|
||||
|
||||
type Collector struct{}
|
||||
|
||||
// Collect implements agent.MetadataCollector
|
||||
func (c *Collector) Collect(ctx context.Context) (string, string, error) {
|
||||
buildInfo, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return "", "", errors.WithStack(metadata.ErrMetadataNotAvailable)
|
||||
}
|
||||
|
||||
return MetadataBuildInfo, buildInfo.String(), nil
|
||||
}
|
||||
|
||||
func NewCollector() *Collector {
|
||||
return &Collector{}
|
||||
}
|
||||
|
||||
var _ metadata.Collector = &Collector{}
|
46
internal/agent/metadata/collector/shell/collector.go
Normal file
46
internal/agent/metadata/collector/shell/collector.go
Normal file
@ -0,0 +1,46 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Collector struct {
|
||||
name string
|
||||
command string
|
||||
args []string
|
||||
}
|
||||
|
||||
// Collect implements agent.MetadataCollector
|
||||
func (c *Collector) Collect(ctx context.Context) (string, string, error) {
|
||||
cmd := exec.CommandContext(ctx, c.command, c.args...)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
value := strings.TrimSpace(buf.String())
|
||||
|
||||
return c.name, value, nil
|
||||
}
|
||||
|
||||
func NewCollector(name string, command string, args ...string) *Collector {
|
||||
return &Collector{
|
||||
name: name,
|
||||
command: command,
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
var _ metadata.Collector = &Collector{}
|
3
internal/agent/metadata/metadata.go
Normal file
3
internal/agent/metadata/metadata.go
Normal file
@ -0,0 +1,3 @@
|
||||
package metadata
|
||||
|
||||
type Metadata map[string]any
|
37
internal/agent/metadata/sort.go
Normal file
37
internal/agent/metadata/sort.go
Normal file
@ -0,0 +1,37 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
type Tuple struct {
|
||||
Key string `json:"key"`
|
||||
Value any `json:"value"`
|
||||
}
|
||||
|
||||
func Sort(metadata map[string]any) []Tuple {
|
||||
keys := make([]string, 0, len(metadata))
|
||||
for k := range metadata {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
tuples := make([]Tuple, len(keys))
|
||||
|
||||
for i, k := range keys {
|
||||
tuples[i] = Tuple{k, metadata[k]}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
func FromSorted(tuples []Tuple) map[string]any {
|
||||
metadata := make(map[string]any)
|
||||
|
||||
for _, t := range tuples {
|
||||
metadata[t.Key] = t.Value
|
||||
}
|
||||
|
||||
return metadata
|
||||
}
|
Reference in New Issue
Block a user