Skip to content

Commit 9340aa8

Browse files
authored
Merge pull request #98 from netboxlabs/develop
release 2.0.0 🚀
2 parents fdb25fb + d51752c commit 9340aa8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+7549
-1712
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ ifdef pv
3535
docker volume ls -f name=orb -f dangling=true -q | xargs -r docker volume rm
3636
endif
3737

38+
.PHONY: install-dev-tools
39+
install-dev-tools:
40+
@go install github.com/mfridman/tparse@latest
41+
3842

3943
agent_bin:
4044
echo "ORB_VERSION: $(ORB_VERSION)-$(COMMIT_HASH)"

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ Currently, only the `local` and `git` sources are supported for config manager.
2828
- [Local](./docs/configs/local.md)
2929
- [Git](./docs/configs/git.md)
3030

31+
### Secrets Manager
32+
The `secrets_manager` section specifies how Orb agent should retrieve and inject secrets into policies. The secrets manager can reference external secret stores like HashiCorp Vault to retrieve sensitive information such as credentials without hardcoding them in configuration files.
33+
34+
```yaml
35+
orb:
36+
secrets_manager:
37+
active: vault
38+
sources:
39+
vault:
40+
address: "https://vault.example.com:8200"
41+
namespace: "my-namespace"
42+
timeout: 60
43+
auth: "token"
44+
auth_args:
45+
token: "${VAULT_TOKEN}"
46+
schedule: "*/5 * * * *"
47+
...
48+
```
49+
50+
Supported secrets managers:
51+
- [HashiCorp Vault](./docs/secretsmgr/vault.md)
52+
3153
### Backends
3254
The `backends` section specifies what Orb agent backends should be enabled. Each Orb agent backend offers specific discovery or observability capabilities and may require specific configuration information.
3355

@@ -52,7 +74,8 @@ A special `common` subsection under `backends` defines configuration settings th
5274
common:
5375
diode:
5476
target: grpc://192.168.0.22:8080/diode
55-
api_key: ${DIODE_API_KEY}
77+
client_id: ${DIODE_CLIENT_ID}
78+
client_secret: ${DIODE_CLIENT_SECRET}
5679
agent_name: agent01
5780
```
5881

agent/agent.go

Lines changed: 88 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"log/slog"
78
"runtime"
89
"time"
910

1011
"github.com/google/uuid"
11-
"github.com/mitchellh/mapstructure"
12-
"go.uber.org/zap"
12+
"gopkg.in/yaml.v3"
1313

1414
"github.com/netboxlabs/orb-agent/agent/backend"
1515
"github.com/netboxlabs/orb-agent/agent/config"
1616
"github.com/netboxlabs/orb-agent/agent/configmgr"
1717
"github.com/netboxlabs/orb-agent/agent/policymgr"
18+
"github.com/netboxlabs/orb-agent/agent/secretsmgr"
1819
"github.com/netboxlabs/orb-agent/agent/version"
1920
)
2021

@@ -29,7 +30,7 @@ type Agent interface {
2930
}
3031

3132
type orbAgent struct {
32-
logger *zap.Logger
33+
logger *slog.Logger
3334
config config.Config
3435
backends map[string]backend.Backend
3536
backendState map[string]*backend.State
@@ -49,8 +50,9 @@ type orbAgent struct {
4950
// AgentGroup channels sent from core
5051
groupsInfos map[string]groupInfo
5152

52-
policyManager policymgr.PolicyManager
53-
configManager configmgr.Manager
53+
policyManager policymgr.PolicyManager
54+
configManager configmgr.Manager
55+
secretsManager secretsmgr.Manager
5456
}
5557

5658
type groupInfo struct {
@@ -61,49 +63,68 @@ type groupInfo struct {
6163
var _ Agent = (*orbAgent)(nil)
6264

6365
// New creates a new agent
64-
func New(logger *zap.Logger, c config.Config) (Agent, error) {
65-
pm, err := policymgr.New(logger, c)
66+
func New(logger *slog.Logger, c config.Config) (Agent, error) {
67+
sm := secretsmgr.New(logger, c.OrbAgent.SecretsManger)
68+
pm, err := policymgr.New(logger, sm, c)
6669
if err != nil {
67-
logger.Error("error during create policy manager, exiting", zap.Error(err))
70+
logger.Error("error during create policy manager, exiting", slog.Any("error", err))
6871
return nil, err
6972
}
7073
if pm.GetRepo() == nil {
71-
logger.Error("policy manager failed to get repository", zap.Error(err))
74+
logger.Error("policy manager failed to get repository", slog.Any("error", err))
7275
return nil, err
7376
}
74-
cm := configmgr.New(logger, pm, c.OrbAgent.ConfigManager)
7577

76-
return &orbAgent{logger: logger, config: c, policyManager: pm, configManager: cm, groupsInfos: make(map[string]groupInfo)}, nil
78+
cm := configmgr.New(logger, pm, c.OrbAgent.ConfigManager.Active)
79+
80+
return &orbAgent{
81+
logger: logger, config: c, policyManager: pm, configManager: cm,
82+
secretsManager: sm, groupsInfos: make(map[string]groupInfo),
83+
}, nil
7784
}
7885

79-
func (a *orbAgent) startBackends(agentCtx context.Context) error {
80-
a.logger.Info("registered backends", zap.Strings("values", backend.GetList()))
81-
a.logger.Info("requested backends", zap.Any("values", a.config.OrbAgent.Backends))
82-
if len(a.config.OrbAgent.Backends) == 0 {
86+
func (a *orbAgent) startBackends(agentCtx context.Context, cfgBackends map[string]any, labels map[string]string) error {
87+
a.logger.Info("registered backends", slog.Any("values", backend.GetList()))
88+
if len(cfgBackends) == 0 {
8389
return errors.New("no backends specified")
8490
}
85-
a.backends = make(map[string]backend.Backend, len(a.config.OrbAgent.Backends))
91+
a.backends = make(map[string]backend.Backend, len(cfgBackends))
8692
a.backendState = make(map[string]*backend.State)
8793

8894
var commonConfig config.BackendCommons
89-
if v, prs := a.config.OrbAgent.Backends["common"]; prs {
90-
if err := mapstructure.Decode(v, &commonConfig); err != nil {
91-
return fmt.Errorf("failed to decode common backend config: %w", err)
95+
if v, prs := cfgBackends["common"]; prs {
96+
bytes, err := yaml.Marshal(v)
97+
if err != nil {
98+
return err
9299
}
100+
err = yaml.Unmarshal(bytes, &commonConfig)
101+
if err != nil {
102+
a.logger.Info("failed to marshal common backend config", slog.Any("error", err))
103+
return err
104+
}
105+
} else {
106+
commonConfig = config.BackendCommons{}
93107
}
94-
commonConfig.Otel.AgentLabels = a.config.OrbAgent.Labels
108+
commonConfig.Otel.AgentLabels = labels
95109
a.backendsCommon = commonConfig
96-
delete(a.config.OrbAgent.Backends, "common")
97-
98-
for name, configurationEntry := range a.config.OrbAgent.Backends {
99-
110+
delete(cfgBackends, "common")
111+
112+
for name, configurationEntry := range cfgBackends {
113+
var cEntity map[string]any
114+
if configurationEntry != nil {
115+
var ok bool
116+
cEntity, ok = configurationEntry.(map[string]any)
117+
if !ok {
118+
return errors.New("invalid backend configuration format for backend: " + name)
119+
}
120+
}
100121
if !backend.HaveBackend(name) {
101122
return errors.New("specified backend does not exist: " + name)
102123
}
103124
be := backend.GetBackend(name)
104125

105-
if err := be.Configure(a.logger, a.policyManager.GetRepo(), configurationEntry, a.backendsCommon); err != nil {
106-
a.logger.Info("failed to configure backend", zap.String("backend", name), zap.Error(err))
126+
if err := be.Configure(a.logger, a.policyManager.GetRepo(), cEntity, a.backendsCommon); err != nil {
127+
a.logger.Info("failed to configure backend", slog.String("backend", name), slog.Any("error", err))
107128
return err
108129
}
109130
backendCtx := context.WithValue(agentCtx, routineKey, name)
@@ -115,7 +136,7 @@ func (a *orbAgent) startBackends(agentCtx context.Context) error {
115136
LastRestartTS: time.Now(),
116137
}
117138
if err := be.Start(context.WithCancel(backendCtx)); err != nil {
118-
a.logger.Info("failed to start backend", zap.String("backend", name), zap.Error(err))
139+
a.logger.Info("failed to start backend", slog.String("backend", name), slog.Any("error", err))
119140
var errMessage string
120141
if initialState == backend.BackendError {
121142
errMessage = err.Error()
@@ -134,20 +155,33 @@ func (a *orbAgent) startBackends(agentCtx context.Context) error {
134155
func (a *orbAgent) Start(ctx context.Context, cancelFunc context.CancelFunc) error {
135156
startTime := time.Now()
136157
defer func(t time.Time) {
137-
a.logger.Debug("Startup of agent execution duration", zap.String("Start() execution duration", time.Since(t).String()))
158+
a.logger.Debug("Startup of agent execution duration", slog.String("Start() execution duration", time.Since(t).String()))
138159
}(startTime)
139160
agentCtx := context.WithValue(ctx, routineKey, "agentRoutine")
140161
asyncCtx, cancelAllAsync := context.WithCancel(context.WithValue(ctx, routineKey, "asyncParent"))
141162
a.asyncContext = asyncCtx
142163
a.rpcFromCancelFunc = cancelAllAsync
143164
a.cancelFunction = cancelFunc
144-
a.logger.Info("agent started", zap.String("version", version.GetBuildVersion()), zap.Any("routine", agentCtx.Value(routineKey)))
165+
a.logger.Info("agent started", slog.String("version", version.GetBuildVersion()), slog.Any("routine", agentCtx.Value(routineKey)))
166+
a.logger.Info("requested backends", slog.Any("values", a.config.OrbAgent.Backends))
145167

146-
if err := a.startBackends(ctx); err != nil {
168+
if err := a.secretsManager.Start(ctx); err != nil {
169+
a.logger.Error("error during start secrets manager", slog.Any("error", err))
147170
return err
148171
}
149172

150-
if err := a.configManager.Start(a.config, a.backends); err != nil {
173+
var err error
174+
if a.config.OrbAgent.Backends,
175+
a.config.OrbAgent.ConfigManager,
176+
err = a.secretsManager.SolveConfigSecrets(a.config.OrbAgent.Backends, a.config.OrbAgent.ConfigManager); err != nil {
177+
return err
178+
}
179+
180+
if err = a.startBackends(ctx, a.config.OrbAgent.Backends, a.config.OrbAgent.Labels); err != nil {
181+
return err
182+
}
183+
184+
if err = a.configManager.Start(a.config, a.backends); err != nil {
151185
return err
152186
}
153187

@@ -162,27 +196,27 @@ func (a *orbAgent) logonWithHeartbeat() {
162196
}
163197

164198
func (a *orbAgent) logoffWithHeartbeat(ctx context.Context) {
165-
a.logger.Debug("stopping heartbeat, going offline status", zap.Any("routine", ctx.Value(routineKey)))
199+
a.logger.Debug("stopping heartbeat, going offline status", slog.Any("routine", ctx.Value(routineKey)))
166200
if a.heartbeatCtx != nil {
167201
a.heartbeatCancel()
168202
}
169203
}
170204

171205
func (a *orbAgent) Stop(ctx context.Context) {
172-
a.logger.Info("routine call for stop agent", zap.Any("routine", ctx.Value(routineKey)))
206+
a.logger.Info("routine call for stop agent", slog.Any("routine", ctx.Value(routineKey)))
173207
if a.rpcFromCancelFunc != nil {
174208
a.rpcFromCancelFunc()
175209
}
176210
for name, b := range a.backends {
177211
if state, _, _ := b.GetRunningStatus(); state == backend.Running {
178-
a.logger.Debug("stopping backend", zap.String("backend", name))
212+
a.logger.Debug("stopping backend", slog.String("backend", name))
179213
if err := b.Stop(ctx); err != nil {
180-
a.logger.Error("error while stopping the backend", zap.String("backend", name))
214+
a.logger.Error("error while stopping the backend", slog.String("backend", name))
181215
}
182216
}
183217
}
184218
a.logoffWithHeartbeat(ctx)
185-
a.logger.Debug("stopping agent with number of go routines and go calls", zap.Int("goroutines", runtime.NumGoroutine()), zap.Int64("gocalls", runtime.NumCgoCall()))
219+
a.logger.Debug("stopping agent with number of go routines and go calls", slog.Int("goroutines", runtime.NumGoroutine()), slog.Int64("gocalls", runtime.NumCgoCall()))
186220
if a.policyRequestSucceeded != nil {
187221
a.policyRequestSucceeded()
188222
}
@@ -198,22 +232,30 @@ func (a *orbAgent) RestartBackend(ctx context.Context, name string, reason strin
198232
}
199233

200234
be := a.backends[name]
201-
a.logger.Info("restarting backend", zap.String("backend", name), zap.String("reason", reason))
235+
a.logger.Info("restarting backend", slog.String("backend", name), slog.String("reason", reason))
202236
a.backendState[name].RestartCount++
203237
a.backendState[name].LastRestartTS = time.Now()
204238
a.backendState[name].LastRestartReason = reason
205-
a.logger.Info("removing policies", zap.String("backend", name))
239+
a.logger.Info("removing policies", slog.String("backend", name))
206240
if err := a.policyManager.RemoveBackendPolicies(be, true); err != nil {
207-
a.logger.Error("failed to remove policies", zap.String("backend", name), zap.Error(err))
241+
a.logger.Error("failed to remove policies", slog.String("backend", name), slog.Any("error", err))
242+
}
243+
var beConfig map[string]any
244+
if a.config.OrbAgent.Backends[name] != nil {
245+
var ok bool
246+
beConfig, ok = a.config.OrbAgent.Backends[name].(map[string]any)
247+
if !ok {
248+
return errors.New("backend not found: " + name)
249+
}
208250
}
209-
if err := be.Configure(a.logger, a.policyManager.GetRepo(), a.config.OrbAgent.Backends[name], a.backendsCommon); err != nil {
251+
if err := be.Configure(a.logger, a.policyManager.GetRepo(), beConfig, a.backendsCommon); err != nil {
210252
return err
211253
}
212-
a.logger.Info("resetting backend", zap.String("backend", name))
254+
a.logger.Info("resetting backend", slog.String("backend", name))
213255

214256
if err := be.FullReset(ctx); err != nil {
215257
a.backendState[name].LastError = fmt.Sprintf("failed to reset backend: %v", err)
216-
a.logger.Error("failed to reset backend", zap.String("backend", name), zap.Error(err))
258+
a.logger.Error("failed to reset backend", slog.String("backend", name), slog.Any("error", err))
217259
}
218260

219261
return nil
@@ -222,12 +264,12 @@ func (a *orbAgent) RestartBackend(ctx context.Context, name string, reason strin
222264
func (a *orbAgent) RestartAll(ctx context.Context, reason string) error {
223265
ctx = a.configManager.GetContext(ctx)
224266
a.logoffWithHeartbeat(ctx)
225-
a.logger.Info("restarting comms", zap.String("reason", reason))
267+
a.logger.Info("restarting comms", slog.String("reason", reason))
226268
for name := range a.backends {
227-
a.logger.Info("restarting backend", zap.String("backend", name), zap.String("reason", reason))
269+
a.logger.Info("restarting backend", slog.String("backend", name), slog.String("reason", reason))
228270
err := a.RestartBackend(ctx, name, reason)
229271
if err != nil {
230-
a.logger.Error("failed to restart backend", zap.Error(err))
272+
a.logger.Error("failed to restart backend", slog.Any("error", err))
231273
}
232274
}
233275
a.logger.Info("all backends and comms were restarted")
@@ -237,6 +279,6 @@ func (a *orbAgent) RestartAll(ctx context.Context, reason string) error {
237279

238280
func (a *orbAgent) extendContext(routine string) (context.Context, context.CancelFunc) {
239281
uuidTraceID := uuid.NewString()
240-
a.logger.Debug("creating context for receiving message", zap.String("routine", routine), zap.String("trace-id", uuidTraceID))
282+
a.logger.Debug("creating context for receiving message", slog.String("routine", routine), slog.String("trace-id", uuidTraceID))
241283
return context.WithCancel(context.WithValue(context.WithValue(a.asyncContext, routineKey, routine), config.ContextKey("trace-id"), uuidTraceID))
242284
}

agent/agent_prof_test.go

Lines changed: 0 additions & 28 deletions
This file was deleted.

agent/backend/backend.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ package backend
22

33
import (
44
"context"
5+
"log/slog"
56
"time"
67

7-
"go.uber.org/zap"
8-
98
"github.com/netboxlabs/orb-agent/agent/config"
109
"github.com/netboxlabs/orb-agent/agent/policies"
1110
)
@@ -47,14 +46,14 @@ func (s RunningStatus) String() string {
4746

4847
// Backend is the interface that all backends must implement
4948
type Backend interface {
50-
Configure(*zap.Logger, policies.PolicyRepo, map[string]interface{}, config.BackendCommons) error
49+
Configure(*slog.Logger, policies.PolicyRepo, map[string]any, config.BackendCommons) error
5150
Version() (string, error)
5251
Start(ctx context.Context, cancelFunc context.CancelFunc) error
5352
Stop(ctx context.Context) error
5453
FullReset(ctx context.Context) error
5554

5655
GetStartTime() time.Time
57-
GetCapabilities() (map[string]interface{}, error)
56+
GetCapabilities() (map[string]any, error)
5857
GetRunningStatus() (RunningStatus, string, error)
5958
GetInitialState() RunningStatus
6059

0 commit comments

Comments
 (0)