Skip to content
Open
Show file tree
Hide file tree
Changes from 96 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
0653f79
feat(gnmi-discovery): initialize go module
leoparente Jun 2, 2026
0363e95
feat(gnmi-discovery): add version, env, logger from snmp-discovery
leoparente Jun 2, 2026
780cbd8
feat(gnmi-discovery): metrics package + nil-safe gNMI accessors
leoparente Jun 2, 2026
1e07864
feat(gnmi-discovery): minimal config types
leoparente Jun 2, 2026
a76861f
feat(gnmi-discovery): no-op policy manager and runner
leoparente Jun 2, 2026
1eb0918
feat(gnmi-discovery): http server adapted from snmp-discovery
leoparente Jun 2, 2026
4305b7e
feat(gnmi-discovery): cmd entrypoint on port 8074
leoparente Jun 2, 2026
35f4b88
chore(gnmi-discovery): go mod tidy + fix version.go comments
leoparente Jun 2, 2026
467211e
fix(gnmi-discovery): record request status metric after c.Next()
leoparente Jun 2, 2026
709fdea
feat(gnmi-discovery): full gNMI policy config schema
leoparente Jun 2, 2026
a9ffea3
feat(gnmi-discovery): policy validation, defaults, env resolution
leoparente Jun 2, 2026
a32dfca
fix(gnmi-discovery): clone slices in MergeDefaults to avoid config al…
leoparente Jun 2, 2026
f4f0645
feat(gnmi-discovery): layered OpenConfig profile loader and matcher
leoparente Jun 3, 2026
da486a9
feat(gnmi-discovery): gNMI Session interface, Notification type, and …
leoparente Jun 3, 2026
58405cf
feat(gnmi-discovery): gnmic-backed gNMI session implementation
leoparente Jun 3, 2026
511a957
fix(gnmi-discovery): document Close invariant + origin handling, deco…
leoparente Jun 3, 2026
d3cedee
feat(gnmi-discovery): in-memory device model with generation pruning
leoparente Jun 3, 2026
b32465e
feat(gnmi-discovery): leak-free single-owner debouncer
leoparente Jun 3, 2026
c5082d9
feat(gnmi-discovery): path/list-key parsing helpers for translation
leoparente Jun 3, 2026
f2d8aa9
feat(gnmi-discovery): per-flush run store and run_id annotation
leoparente Jun 3, 2026
87893ae
test(gnmi-discovery): cover run-id annotation, newest-first runs, sla…
leoparente Jun 3, 2026
d398854
feat(gnmi-discovery): event-driven runner with auto-fallback and reco…
leoparente Jun 3, 2026
fbc5cb4
test(gnmi-discovery): runner auto-fallback, sync-gate, run-id, resp.E…
leoparente Jun 3, 2026
f9ce309
feat(gnmi-discovery): full _base + arista/nokia profiles
leoparente Jun 3, 2026
c46e46e
test(gnmi-discovery): dry-run golden test from canned EOS stream
leoparente Jun 3, 2026
ec0e93e
feat(gnmi-discovery): dockerfile, makefile, readme
leoparente Jun 3, 2026
8499b2d
fix(gnmi-discovery): stop gnmic subscribe goroutine leak on reconnect…
leoparente Jun 3, 2026
46bdbcd
fix(gnmi-discovery): getStatus race, uint mtu decode, idempotent metr…
leoparente Jun 3, 2026
5ee7dc2
fix(gnmi-discovery): auto-fallback downgrades on async on_change reje…
leoparente Jun 3, 2026
fdf4952
fix(gnmi-discovery): reject negative intervals (prevent NewTicker pan…
leoparente Jun 3, 2026
31278f2
ci(gnmi-discovery): add lint and test workflows
leoparente Jun 3, 2026
31bd789
fix(gnmi-discovery): drain buffered early-failure error on notes-clos…
leoparente Jun 3, 2026
f06e951
fix(gnmi-discovery): cancel prior subscription on re-Subscribe (auto-…
leoparente Jun 3, 2026
3af418c
fix(gnmi-discovery): redact policy debug log, close Start/Stop wg rac…
leoparente Jun 3, 2026
cf4737d
fix(gnmi-discovery): gate first SAMPLE flush on sync_response (avoid …
leoparente Jun 3, 2026
22cd687
fix(gnmi-discovery): trigger flush on SAMPLE sync, teardown prior sub…
leoparente Jun 3, 2026
aef5476
fix(gnmi-discovery): reject overflowing interval values (prevent NewT…
leoparente Jun 3, 2026
427ed04
feat(gnmi-discovery): first-class NVIDIA Cumulus profile (vendor alia…
leoparente Jun 3, 2026
a186740
feat(gnmi-discovery): capture chassis serial (Device.Serial) and soft…
leoparente Jun 3, 2026
68d4831
feat(gnmi-discovery): attach manufacturer to Platform (parity with sn…
leoparente Jun 3, 2026
0d0cad4
feat(gnmi-discovery): discover manufacturer (chassis mfg-name + capab…
leoparente Jun 3, 2026
0856b37
fix(gnmi-discovery): normalize OpenConfig component-type identityref …
leoparente Jun 3, 2026
eb5e960
feat(gnmi-discovery): discover interface type from OpenConfig + user …
leoparente Jun 3, 2026
2d3a4a3
feat(gnmi-discovery): OpenConfig subinterface IP path parser
leoparente Jun 5, 2026
5de6edd
feat(gnmi-discovery): always subscribe+permit the OpenConfig IP subtree
leoparente Jun 5, 2026
81f9dee
feat(gnmi-discovery): translate subinterface IPv4/IPv6 to NetBox IPAd…
leoparente Jun 5, 2026
01582bf
feat(gnmi-discovery): primary IP from target-host match
leoparente Jun 5, 2026
5fb6b24
feat(gnmi-discovery): stamp run_id on IPAddress entities
leoparente Jun 5, 2026
09f4ec5
feat(gnmi-discovery): set device primary IP from the policy target host
leoparente Jun 5, 2026
c1773a8
docs(gnmi-discovery): note OpenConfig assumption for always-on IP sub…
leoparente Jun 5, 2026
170589e
chore(gnmi-discovery): bump dependencies to latest + fix lint
leoparente Jun 5, 2026
c39a1ba
test(gnmi-discovery): raise unit-test coverage to >=90% per in-scope …
leoparente Jun 6, 2026
8339045
test(gnmi-discovery): cover gnmic transport against in-process gNMI s…
leoparente Jun 6, 2026
459e4e3
test(gnmi-discovery): address review findings on the coverage tests
leoparente Jun 6, 2026
9a55b92
feat(gnmi-discovery): interface type ladder + speed lookup tables
leoparente Jun 7, 2026
aaca5eb
feat(gnmi-discovery): subscribe+permit ethernet speed/mac/aggregate-i…
leoparente Jun 7, 2026
45c325c
feat(gnmi-discovery): populate Interface speed/MAC/LAG + ladder-based…
leoparente Jun 7, 2026
3ab0e86
feat(gnmi-discovery): stamp run_id on Interface.Lag references
leoparente Jun 7, 2026
4de5620
refactor(gnmi-discovery): drop ambiguous Juniper et- name rule + guar…
leoparente Jun 7, 2026
6747f32
feat(gnmi-discovery): OpenConfig switched-vlan parser + trunk-vlan ex…
leoparente Jun 8, 2026
31bb51b
feat(gnmi-discovery): always subscribe+permit the OpenConfig switched…
leoparente Jun 8, 2026
c9041e4
feat(gnmi-discovery): translate switchport mode + untagged/tagged VLA…
leoparente Jun 8, 2026
fe1bd49
feat(gnmi-discovery): stamp run_id on VLAN entities + interface vlan …
leoparente Jun 8, 2026
d945eb9
fix(gnmi-discovery): decode native gNMI leaf-list TypedValue
leoparente Jun 8, 2026
1c3ec2f
feat(gnmi-discovery): vlan defaults block (group/tenant/role/tags/des…
leoparente Jun 8, 2026
fa5a51b
feat(gnmi-discovery): network-instance VLAN parser + shared VLAN builder
leoparente Jun 8, 2026
cf248ca
feat(gnmi-discovery): subscribe+permit the OpenConfig network-instanc…
leoparente Jun 8, 2026
3d08ae0
feat(gnmi-discovery): real VLAN names/status + full VLAN inventory vi…
leoparente Jun 8, 2026
a9d01e7
fix(gnmi-discovery): guard VLANGroup.Scope against typed-nil site
leoparente Jun 8, 2026
191fac5
feat(gnmi-discovery): network-instance L3VRF parser + translateVrfs
leoparente Jun 8, 2026
ea58237
feat(gnmi-discovery): subscribe+permit network-instance VRF state/mem…
leoparente Jun 8, 2026
e4ec426
feat(gnmi-discovery): emit VRFs + bind Interface.Vrf/IPAddress.Vrf (s…
leoparente Jun 8, 2026
7c895c0
feat(gnmi-discovery): stamp run_id on VRF entities + interface/IP vrf…
leoparente Jun 8, 2026
ca79e9e
feat(gnmi-discovery): prefix defaults block (role/tenant/tags/descrip…
leoparente Jun 8, 2026
ff67b16
feat(gnmi-discovery): derive connected Prefix entities from discovere…
leoparente Jun 8, 2026
b3f867b
feat(gnmi-discovery): emit connected prefixes in Translate (after VRF…
leoparente Jun 8, 2026
2fac063
feat(gnmi-discovery): stamp run_id on Prefix entities
leoparente Jun 8, 2026
a2cb8d8
feat(gnmi-discovery): discover interface duplex from OpenConfig negot…
leoparente Jun 8, 2026
c177928
feat(gnmi-discovery): recognize Dell + SONiC vendors and log selected…
leoparente Jun 8, 2026
0d6accb
feat(gnmi-discovery): Huawei + PortChannel interface-name type patterns
leoparente Jun 8, 2026
ac10e88
feat(gnmi-discovery): Cisco/Juniper/Huawei/Dell/SONiC profile overlays
leoparente Jun 8, 2026
3135b2e
refactor(gnmi-discovery): decouple NOS profile selection from manufac…
leoparente Jun 8, 2026
e93b412
Merge remote-tracking branch 'origin/develop' into feat/gnmi-discover…
leoparente Jun 9, 2026
a3b0a5c
ci(gnmi-discovery): align workflows with modernized per-backend CI
leoparente Jun 9, 2026
336add1
go mod update
leoparente Jun 9, 2026
8da270a
fix(gnmi-discovery): address PR review feedback and bump Go to 1.26.4
leoparente Jun 9, 2026
15f451e
fix(gnmi-discovery): address follow-up PR review
leoparente Jun 9, 2026
db19ca7
Merge remote-tracking branch 'origin/develop' into feat/gnmi-discover…
leoparente Jun 9, 2026
df82131
fix(gnmi-discovery): address review (413, DELETE race, OTEL env, docs)
leoparente Jun 9, 2026
fb90843
Merge remote-tracking branch 'origin/develop' into feat/gnmi-discover…
leoparente Jun 12, 2026
72ac5cc
fix(gnmi-discovery): inherit parent match on override merge; tighten …
leoparente Jun 12, 2026
e72e327
ci(gnmi-discovery): build release image without pushing (no DockerHub…
leoparente Jun 12, 2026
7c2cc99
fix(gnmi-discovery): honor skip_verify with TLS material, guard float…
leoparente Jun 12, 2026
9350806
fix(gnmi-discovery): valid branch filters, preserve early-stream erro…
leoparente Jun 12, 2026
a3d6fa6
fix(gnmi-discovery): TLS secure by default, explicit insecure opt-in …
leoparente Jun 12, 2026
e469f4e
fix(gnmi-discovery): use copied stat for uptime; ensurePort handles z…
leoparente Jun 12, 2026
8f3ba86
fix(gnmi-discovery): reject empty interface_patterns type; README snm…
leoparente Jun 12, 2026
6aab305
fix(gnmi-discovery): apply interface_exclude_patterns to IP/prefix tr…
leoparente Jun 12, 2026
f96774b
fix(gnmi-discovery): bad profile override falls back to the bundled p…
leoparente Jun 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/gnmi-discovery-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: gNMI Discovery - lint
on:
push:
branches-ignore:
- release
paths:
- "gnmi-discovery/**"
- "!gnmi-discovery/docker/**"
pull_request:
paths:
- "gnmi-discovery/**"
- "!gnmi-discovery/docker/**"

permissions:
contents: read

jobs:
golangci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: 'gnmi-discovery/go.mod'
- name: Lint
uses: golangci/golangci-lint-action@db582008a42febd596419635a5abc9d9815daa9c # v9.2.1
with:
version: v2.11.3
working-directory: gnmi-discovery
args: --config ../.github/golangci.yaml
248 changes: 248 additions & 0 deletions .github/workflows/gnmi-discovery-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
name: gNMI Discovery - release
on:
workflow_dispatch:
push:
branches: [ release ]
paths:
- "gnmi-discovery/**"
- "!gnmi-discovery/docker/**"

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SEMANTIC_RELEASE_PACKAGE: ${{ github.repository }}
APP_NAME: gnmi-discovery

permissions:
contents: write
issues: write
pull-requests: write

jobs:
get-next-version:
name: Semantic release get next version
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: "lts/*"
- name: Write package.json
run: |
cat > "${{ env.APP_NAME }}/package.json" <<'EOF'
{
"name": "${{ env.APP_NAME }}",
"version": "1.0.0",
"devDependencies": {
"semantic-release": "^25.0.0-beta.6",
"semantic-release-export-data": "^1.0.1",
"semantic-release-monorepo": "^8.0.0",
"@semantic-release/changelog": "^6.0.3"
}
}
EOF
- name: Write .releaserc.json
run: |
cat > "${{ env.APP_NAME }}/.releaserc.json" <<'EOF'
{
"extends": "semantic-release-monorepo",
"branches": "release",
"repositoryUrl": "https://github.com/netboxlabs/orb-discovery",
"debug": "true",
"tagFormat": "${{ env.APP_NAME }}/v${version}",
"plugins": [
["semantic-release-export-data"],
["@semantic-release/commit-analyzer", {
"releaseRules": [
{ "breaking": true, "release": "major" },
{ "type": "fix", "release": "patch" },
{ "type": "feat", "release": "minor" },
{ "type": "perf", "release": "patch" },
{ "type": "chore", "scope": "deps", "release": "patch" }
]
}],
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md",
"changelogTitle": "# Semantic Versioning Changelog"
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "release/**"
}
]
}
]
]
}
EOF
- name: setup semantic-release
working-directory: ${{ env.APP_NAME }}
run: npm install --legacy-peer-deps
- name: release dry-run
working-directory: ${{ env.APP_NAME }}
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_SEMANTIC_RELEASE_WEBHOOK }}
run: npx semantic-release --debug --dry-run
id: get-next-version
- name: Set short sha output
id: short-sha
run: echo "short-sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
- name: Set release version
id: release-version
run: |
echo "release-version=$(echo '${{ steps.get-next-version.outputs.new-release-version }}' | sed -E 's|^${{ env.APP_NAME }}[-/]||; s|^v||')" >> "$GITHUB_OUTPUT"
outputs:
new-release-published: ${{ steps.get-next-version.outputs.new-release-published }}
new-release-version: ${{ steps.release-version.outputs.release-version }}
short-sha: ${{ steps.short-sha.outputs.short-sha }}

confirm-version:
name: Next version ${{ needs.get-next-version.outputs.new-release-version }}
runs-on: ubuntu-latest
timeout-minutes: 5
needs: get-next-version
if: needs.get-next-version.outputs.new-release-published == 'true'
steps:
- uses: actions/checkout@v6
- run: echo "The new release version is ${{ needs.get-next-version.outputs.new-release-version }} commit ${{ needs.get-next-version.outputs.short-sha }}"

build:
name: Build
needs: get-next-version
runs-on: ubuntu-latest
strategy:
fail-fast: false
if: needs.get-next-version.outputs.new-release-published == 'true'
env:
BUILD_VERSION: ${{ needs.get-next-version.outputs.new-release-version }}
BUILD_COMMIT: ${{ needs.get-next-version.outputs.short-sha }}
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Extract Go version from go.mod
run: echo "GO_VERSION=$(grep '^go ' gnmi-discovery/go.mod | awk '{print $2}')" >> $GITHUB_ENV

- name: Set up QEMU
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

- name: Login to Docker Hub
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set build info
run: |
echo $BUILD_COMMIT > ./gnmi-discovery/version/BUILD_COMMIT.txt
echo $BUILD_VERSION > ./gnmi-discovery/version/BUILD_VERSION.txt

# Build only — gnmi-discovery is experimental and has no DockerHub repo yet,
# so push is disabled. This still validates the multi-arch image build.
# Flip push to true (and ensure netboxlabs/gnmi-discovery exists) to publish.
- name: Build image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: gnmi-discovery
file: gnmi-discovery/docker/Dockerfile
platforms: linux/amd64, linux/arm64
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
tags: |
netboxlabs/gnmi-discovery:latest
netboxlabs/gnmi-discovery:${{ env.BUILD_VERSION }}
build-args: |
GO_VERSION=${{ env.GO_VERSION }}

semantic-release:
name: Semantic release
needs: build
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: "lts/*"
- name: Write package.json
run: |
cat > "${{ env.APP_NAME }}/package.json" <<'EOF'
{
"name": "${{ env.APP_NAME }}",
"version": "1.0.0",
"devDependencies": {
"semantic-release": "^25.0.0-beta.6",
"semantic-release-export-data": "^1.0.1",
"semantic-release-monorepo": "^8.0.0",
"@semantic-release/changelog": "^6.0.3"
}
}
EOF
- name: Write .releaserc.json
run: |
cat > "${{ env.APP_NAME }}/.releaserc.json" <<'EOF'
{
"extends": "semantic-release-monorepo",
"branches": "release",
"repositoryUrl": "https://github.com/netboxlabs/orb-discovery",
"debug": "true",
"tagFormat": "${{ env.APP_NAME }}/v${version}",
"plugins": [
["semantic-release-export-data"],
["@semantic-release/commit-analyzer", {
"releaseRules": [
{ "breaking": true, "release": "major" },
{ "type": "fix", "release": "patch" },
{ "type": "feat", "release": "minor" },
{ "type": "perf", "release": "patch" },
{ "type": "chore", "scope": "deps", "release": "patch" }
]
}],
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md",
"changelogTitle": "# Semantic Versioning Changelog"
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "release/**"
}
]
}
]
]
}
EOF
- name: setup semantic-release
working-directory: ${{ env.APP_NAME }}
run: npm install --legacy-peer-deps
- name: Release
working-directory: ${{ env.APP_NAME }}
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_OBSERVABILITY_RELEASE_WEBHOOK }}
run: npx semantic-release --debug
72 changes: 72 additions & 0 deletions .github/workflows/gnmi-discovery-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: gNMI Discovery - test
on:
push:
branches-ignore:
- release
paths:
- "gnmi-discovery/**"
- "!gnmi-discovery/docker/**"
pull_request:
paths:
- "gnmi-discovery/**"
- "!gnmi-discovery/docker/**"

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
contents: write
pull-requests: write

jobs:
go-test:
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: gnmi-discovery
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: 'gnmi-discovery/go.mod'
- name: Run go build
run: go build ./...
- name: Install additional dependencies
run: |
make install-dev-tools
- name: Run go test
id: go-test
run: |
make test-coverage
echo 'coverage-report<<EOF' >> $GITHUB_OUTPUT
cat .coverage/test-report.md >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
echo "coverage-total=$(cat .coverage/coverage.txt)" >> $GITHUB_OUTPUT
- name: Output Result
if: always()
run: cat .coverage/test-report.md
- name: Find comment
# Only on pull_request: on push runs there is no pull_request.number, and
# find-comment v4 coerces the empty input to 0 and fails the job.
if: github.event_name == 'pull_request'
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
id: existing-comment
with:
issue-number: ${{ github.event.pull_request.number }}
Comment thread
leoparente marked this conversation as resolved.
comment-author: 'github-actions[bot]'
body-includes: Go test coverage
- name: Post comment
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
if: github.event.pull_request.head.repo.full_name == github.repository
with:
comment-id: ${{ steps.existing-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
Go test coverage
${{ steps.go-test.outputs.coverage-report }}
Total coverage: ${{ steps.go-test.outputs.coverage-total }}%
edit-mode: replace
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Orb discovery backends collection
- [device-discovery](./device-discovery/README.md) - Device Discovery Backend that uses [NAPALM](https://github.com/napalm-automation/napalm) Drivers.
- [network-discovery](./network-discovery/README.md) - Network Discovery Backend which is a wrapper over [NMAP](https://nmap.org/) scanner.
- [worker](./worker/README.md) - A Worker Backend that allows to run custom implementation as part of Orb Agent.
- [snmp-discover](./snmp-discovery/README.md) - Device discovery that uses SNMP
- [snmp-discover](./snmp-discovery/README.md) - Device discovery that uses SNMP
Comment thread
leoparente marked this conversation as resolved.
Outdated
- [gnmi-discovery](./gnmi-discovery/README.md) - **(experimental)** Event-driven device discovery that uses [gNMI](https://github.com/openconfig/gnmi) subscriptions over [OpenConfig](https://www.openconfig.net/) models.
Loading
Loading