Skip to content

Commit a9f3d3b

Browse files
authored
Merge pull request #54 from netboxlabs/develop
release 🚚
2 parents 798482a + 08b1f26 commit a9f3d3b

22 files changed

+744
-125
lines changed

.github/workflows/develop.yaml

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Orb Agent - develop
2+
on:
3+
workflow_dispatch:
4+
push:
5+
branches: [ develop ]
6+
paths:
7+
- "agent/**"
8+
- "cmd/**"
9+
- "!agent/docker/**"
10+
11+
permissions:
12+
contents: write
13+
14+
env:
15+
GO_VERSION: '1.23'
16+
17+
jobs:
18+
build-and-push:
19+
runs-on: ubuntu-latest
20+
strategy:
21+
fail-fast: false
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Set up QEMU
27+
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf #v3.2.0
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 #v3.8.0
31+
32+
- name: Login to Docker Hub
33+
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0
34+
with:
35+
username: ${{ secrets.DOCKERHUB_USERNAME }}
36+
password: ${{ secrets.DOCKERHUB_TOKEN }}
37+
38+
- name: Set build info
39+
run: |
40+
echo ${GITHUB_SHA::7} > ./agent/version/BUILD_COMMIT.txt
41+
LATEST_RELEASE=$(curl --silent "https://api.github.com/repos/${{ github.repository }}/releases/latest" | jq -r '.tag_name')
42+
echo $LATEST_RELEASE > ./agent/version/BUILD_VERSION.txt
43+
44+
- name: Build image and push
45+
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 #v6.10.0
46+
with:
47+
context: .
48+
file: agent/docker/Dockerfile
49+
platforms: linux/amd64, linux/arm64
50+
push: true
51+
cache-from: type=gha
52+
cache-to: type=gha,mode=max
53+
tags: netboxlabs/orb-agent:develop
54+
build-args: |
55+
GO_VERSION=${{ env.GO_VERSION }}

.github/workflows/lint.yaml

+3-5
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ jobs:
1515
- name: Checkout
1616
uses: actions/checkout@v4
1717
- name: Setup Go
18-
uses: actions/setup-go@v4
18+
uses: actions/setup-go@v5
1919
with:
20-
go-version: '1.23'
20+
go-version: '1.23.x'
2121
check-latest: true
2222
- name: Lint
23-
uses: golangci/golangci-lint-action@v3
23+
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 #v6.1.1
2424
with:
2525
version: v1.62
2626
working-directory: .
2727
args: --config .github/golangci.yaml
28-
skip-pkg-cache: true
29-
skip-build-cache: true

.github/workflows/release.yaml

+9-9
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ concurrency:
1515
env:
1616
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1717
SEMANTIC_RELEASE_PACKAGE: ${{ github.repository }}
18-
GO_VERSION: '1.23'
18+
GO_VERSION: '1.23.x'
1919
APP_NAME: orb-agent
2020

2121
permissions:
@@ -34,7 +34,7 @@ jobs:
3434
with:
3535
node-version: "lts/*"
3636
- name: Write package.json
37-
uses: DamianReeves/write-file-action@master
37+
uses: DamianReeves/write-file-action@6929a9a6d1807689191dcc8bbe62b54d70a32b42 #v1.3
3838
with:
3939
path: ./package.json
4040
write-mode: overwrite
@@ -48,7 +48,7 @@ jobs:
4848
}
4949
}
5050
- name: Write .releaserc.json
51-
uses: DamianReeves/write-file-action@master
51+
uses: DamianReeves/write-file-action@6929a9a6d1807689191dcc8bbe62b54d70a32b42 #v1.3
5252
with:
5353
path: ./.releaserc.json
5454
write-mode: overwrite
@@ -132,13 +132,13 @@ jobs:
132132
uses: actions/checkout@v4
133133

134134
- name: Set up QEMU
135-
uses: docker/setup-qemu-action@v3
135+
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf #v3.2.0
136136

137137
- name: Set up Docker Buildx
138-
uses: docker/setup-buildx-action@v3
138+
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 #v3.8.0
139139

140140
- name: Login to Docker Hub
141-
uses: docker/login-action@v3
141+
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0
142142
with:
143143
username: ${{ secrets.DOCKERHUB_USERNAME }}
144144
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -149,7 +149,7 @@ jobs:
149149
echo $BUILD_VERSION > ./agent/version/BUILD_VERSION.txt
150150
151151
- name: Build image and push
152-
uses: docker/build-push-action@v6
152+
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 #v6.10.0
153153
with:
154154
context: .
155155
file: agent/docker/Dockerfile
@@ -174,7 +174,7 @@ jobs:
174174
with:
175175
node-version: "lts/*"
176176
- name: Write package.json
177-
uses: DamianReeves/write-file-action@master
177+
uses: DamianReeves/write-file-action@6929a9a6d1807689191dcc8bbe62b54d70a32b42 #v1.3
178178
with:
179179
path: ./package.json
180180
write-mode: overwrite
@@ -188,7 +188,7 @@ jobs:
188188
}
189189
}
190190
- name: Write .releaserc.json
191-
uses: DamianReeves/write-file-action@master
191+
uses: DamianReeves/write-file-action@6929a9a6d1807689191dcc8bbe62b54d70a32b42 #v1.3
192192
with:
193193
path: ./.releaserc.json
194194
write-mode: overwrite

.github/workflows/tests.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Orb Agent - test
1+
name: Orb Agent - tests
22
on:
33
push:
44
branches:
@@ -32,9 +32,9 @@ jobs:
3232
- name: Checkout
3333
uses: actions/checkout@v4
3434
- name: Setup Go
35-
uses: actions/setup-go@v4
35+
uses: actions/setup-go@v5
3636
with:
37-
go-version: '1.23'
37+
go-version: '1.23.x'
3838
check-latest: true
3939
- name: Run go build
4040
run: go build ./...
@@ -54,14 +54,14 @@ jobs:
5454
if: always()
5555
run: cat .coverage/test-report.md
5656
- name: Find comment
57-
uses: peter-evans/find-comment@v3
57+
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e #v3.1.0
5858
id: existing-comment
5959
with:
6060
issue-number: ${{ github.event.pull_request.number }}
6161
comment-author: 'github-actions[bot]'
6262
body-includes: Go test coverage
6363
- name: Post comment
64-
uses: peter-evans/create-or-update-comment@v4
64+
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 #v4.0.0
6565
with:
6666
comment-id: ${{ steps.existing-comment.outputs.comment-id }}
6767
issue-number: ${{ github.event.pull_request.number }}

README.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ orb:
3636
network_discovery:
3737
...
3838
```
39-
Only the `network_discovery` and `device_discovery` backends are currently supported. They do not require any special configuration.
39+
Only the `network_discovery`, `device_discovery` and `worker` backends are currently supported. They do not require any special configuration.
4040
- [Device Discovery](./docs/backends/device_discovery.md)
4141
- [Network Discovery](./docs/backends/network_discovery.md)
42+
- [Worker](./docs/backends/worker.md)
4243

4344
#### Common
4445
A special `common` subsection under `backends` defines configuration settings that are shared with all backends. Currently, it supports passing [diode](https://github.com/netboxlabs/diode) server settings to all backends.
@@ -66,14 +67,22 @@ orb:
6667
network_discovery:
6768
network_policy_1:
6869
# see docs/backends/network_discovery.md
70+
worker:
71+
worker_policy_1:
72+
# see docs/backends/worker.md
6973
```
7074

7175
## Running the agent
7276

7377
To run `orb-agent`, use the following command from the directory where your created your `agent.yaml` file:
7478

7579
```sh
76-
docker run -v $(PWD):/opt/orb/ netboxlabs/orb-agent:latest run -c /opt/orb/agent.yaml
80+
docker run --net=host -v $(PWD):/opt/orb/ netboxlabs/orb-agent:latest run -c /opt/orb/agent.yaml
81+
```
82+
The container needs sufficient permissions, to send `icmp` and `tcp` packets. This can either be achieved by setting the network-mode to `host` or by changing the container user to `root`:
83+
84+
```sh
85+
docker run -u root -v $(PWD):/opt/orb/ netboxlabs/orb-agent:latest run -c /opt/orb/agent.yaml
7786
```
7887

7988
### Configuration samples

agent/backend/devicediscovery/device_discovery.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,14 @@ func (d *deviceDiscoveryBackend) Start(ctx context.Context, cancelFunc context.C
109109
"--host", d.apiHost,
110110
"--port", d.apiPort,
111111
"--diode-target", d.diodeTarget,
112-
"--diode-api-key", d.diodeAPIKey,
112+
"--diode-api-key", "********",
113113
"--diode-app-name-prefix", d.diodeAppNamePrefix,
114114
}
115115

116116
d.logger.Info("device-discovery startup", zap.Strings("arguments", pvOptions))
117117

118+
pvOptions[7] = d.diodeAPIKey
119+
118120
d.proc = cmd.NewCmdOptions(cmd.Options{
119121
Buffered: false,
120122
Streaming: true,
@@ -271,14 +273,14 @@ func (d *deviceDiscoveryBackend) ApplyPolicy(data policies.PolicyData, updatePol
271273

272274
policyYaml, err := yaml.Marshal(fullPolicy)
273275
if err != nil {
274-
d.logger.Warn("yaml policy marshal failure", zap.String("policy_id", data.ID), zap.Any("policy", fullPolicy))
276+
d.logger.Warn("policy yaml marshal failure", zap.String("policy_id", data.ID), zap.Any("policy", fullPolicy))
275277
return err
276278
}
277279

278280
var resp map[string]interface{}
279281
err = d.request("policies", &resp, http.MethodPost, bytes.NewBuffer(policyYaml), "application/x-yaml", applyPolicyTimeout)
280282
if err != nil {
281-
d.logger.Warn("yaml policy application failure", zap.String("policy_id", data.ID), zap.ByteString("policy", policyYaml))
283+
d.logger.Warn("policy application failure", zap.String("policy_id", data.ID), zap.ByteString("policy", policyYaml))
282284
return err
283285
}
284286

agent/backend/devicediscovery/utils.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (d *deviceDiscoveryBackend) request(url string, payload interface{}, method
7979
var jsonBody map[string]interface{}
8080
err := json.Unmarshal(body, &jsonBody)
8181
if err == nil {
82-
if errMsg, ok := jsonBody["error"]; ok {
82+
if errMsg, ok := jsonBody["detail"]; ok {
8383
return fmt.Errorf("%d %s", res.StatusCode, errMsg)
8484
}
8585
}

agent/backend/networkdiscovery/network_discovery.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,14 @@ func (d *networkDiscoveryBackend) Start(ctx context.Context, cancelFunc context.
109109
"--host", d.apiHost,
110110
"--port", d.apiPort,
111111
"--diode-target", d.diodeTarget,
112-
"--diode-api-key", d.diodeAPIKey,
112+
"--diode-api-key", "********",
113113
"--diode-app-name-prefix", d.diodeAppNamePrefix,
114114
}
115115

116116
d.logger.Info("network-discovery startup", zap.Strings("arguments", pvOptions))
117117

118+
pvOptions[7] = d.diodeAPIKey
119+
118120
d.proc = cmd.NewCmdOptions(cmd.Options{
119121
Buffered: false,
120122
Streaming: true,
@@ -271,14 +273,14 @@ func (d *networkDiscoveryBackend) ApplyPolicy(data policies.PolicyData, updatePo
271273

272274
policyYaml, err := yaml.Marshal(fullPolicy)
273275
if err != nil {
274-
d.logger.Warn("yaml policy marshal failure", zap.String("policy_id", data.ID), zap.Any("policy", fullPolicy))
276+
d.logger.Warn("policy yaml marshal failure", zap.String("policy_id", data.ID), zap.Any("policy", fullPolicy))
275277
return err
276278
}
277279

278280
var resp map[string]interface{}
279281
err = d.request("policies", &resp, http.MethodPost, bytes.NewBuffer(policyYaml), "application/x-yaml", applyPolicyTimeout)
280282
if err != nil {
281-
d.logger.Warn("yaml policy application failure", zap.String("policy_id", data.ID), zap.ByteString("policy", policyYaml))
283+
d.logger.Warn("policy application failure", zap.String("policy_id", data.ID), zap.ByteString("policy", policyYaml))
282284
return err
283285
}
284286

agent/backend/networkdiscovery/utils.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (d *networkDiscoveryBackend) request(url string, payload interface{}, metho
7979
var jsonBody map[string]interface{}
8080
err := json.Unmarshal(body, &jsonBody)
8181
if err == nil {
82-
if errMsg, ok := jsonBody["error"]; ok {
82+
if errMsg, ok := jsonBody["detail"]; ok {
8383
return fmt.Errorf("%d %s", res.StatusCode, errMsg)
8484
}
8585
}

agent/backend/worker/utils.go

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package worker
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"time"
9+
10+
"go.uber.org/zap"
11+
12+
"github.com/netboxlabs/orb-agent/agent/backend"
13+
)
14+
15+
func (d *workerBackend) getProcRunningStatus() (backend.RunningStatus, string, error) {
16+
if d.proc == nil {
17+
return backend.Unknown, "backend not started yet", nil
18+
}
19+
status := d.proc.Status()
20+
21+
if status.Error != nil {
22+
errMsg := fmt.Sprintf("worker process error: %v", status.Error)
23+
return backend.BackendError, errMsg, status.Error
24+
}
25+
26+
if status.Complete {
27+
err := d.proc.Stop()
28+
return backend.Offline, "worker process ended", err
29+
}
30+
31+
if status.StopTs > 0 {
32+
return backend.Offline, "worker process ended", nil
33+
}
34+
return backend.Running, "", nil
35+
}
36+
37+
// note this needs to be stateless because it is called for multiple go routines
38+
func (d *workerBackend) request(url string, payload interface{}, method string, body io.Reader, contentType string, timeout int32) error {
39+
client := http.Client{
40+
Timeout: time.Second * time.Duration(timeout),
41+
}
42+
43+
status, _, err := d.getProcRunningStatus()
44+
if status != backend.Running {
45+
d.logger.Warn("skipping device discovery REST API request because process is not running or is unresponsive", zap.String("url", url), zap.String("method", method), zap.Error(err))
46+
return err
47+
}
48+
49+
URL := fmt.Sprintf("%s://%s:%s/api/v1/%s", d.apiProtocol, d.apiHost, d.apiPort, url)
50+
51+
req, err := http.NewRequest(method, URL, body)
52+
if err != nil {
53+
d.logger.Error("received error from payload", zap.Error(err))
54+
return err
55+
}
56+
57+
req.Header.Add("Content-Type", contentType)
58+
res, getErr := client.Do(req)
59+
60+
if getErr != nil {
61+
d.logger.Error("received error from payload", zap.Error(getErr))
62+
return getErr
63+
}
64+
65+
defer func() {
66+
if err := res.Body.Close(); err != nil {
67+
d.logger.Error("failed to close response body", zap.Error(err))
68+
}
69+
}()
70+
71+
if (res.StatusCode < 200) || (res.StatusCode > 299) {
72+
body, err := io.ReadAll(res.Body)
73+
if err != nil {
74+
return fmt.Errorf("non 2xx HTTP error code from worker, no or invalid body: %d", res.StatusCode)
75+
}
76+
if len(body) == 0 {
77+
return fmt.Errorf("%d empty body", res.StatusCode)
78+
} else if body[0] == '{' {
79+
var jsonBody map[string]interface{}
80+
err := json.Unmarshal(body, &jsonBody)
81+
if err == nil {
82+
if errMsg, ok := jsonBody["detail"]; ok {
83+
return fmt.Errorf("%d %s", res.StatusCode, errMsg)
84+
}
85+
}
86+
}
87+
}
88+
89+
if res.Body != nil {
90+
err = json.NewDecoder(res.Body).Decode(&payload)
91+
if err != nil {
92+
return err
93+
}
94+
}
95+
return nil
96+
}

0 commit comments

Comments
 (0)