mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-10-12 01:58:46 +02:00
internal/clientinfo: add Ubios custom device name
This commit is contained in:
1 parent
dc700bbd52
commit
0a6d9d4454
3 files changed
+140
-6
No files matched your search
@@ -73,6 +73,7 @@ type Table struct {
|
|||||||
|
|
||||||
dhcp *dhcp
|
dhcp *dhcp
|
||||||
merlin *merlinDiscover
|
merlin *merlinDiscover
|
||||||
|
ubios *ubiosDiscover
|
||||||
arp *arpDiscover
|
arp *arpDiscover
|
||||||
ndp *ndpDiscover
|
ndp *ndpDiscover
|
||||||
ptr *ptrDiscover
|
ptr *ptrDiscover
|
||||||
@@ -138,14 +139,26 @@ func (t *Table) init() {
|
|||||||
// Otherwise, process all possible sources in order, that means
|
// Otherwise, process all possible sources in order, that means
|
||||||
// the first result of IP/MAC/Hostname lookup will be used.
|
// the first result of IP/MAC/Hostname lookup will be used.
|
||||||
//
|
//
|
||||||
// Merlin custom clients.
|
// Routers custom clients:
|
||||||
|
// - Merlin
|
||||||
|
// - Ubios
|
||||||
if t.discoverDHCP() || t.discoverARP() {
|
if t.discoverDHCP() || t.discoverARP() {
|
||||||
t.merlin = &merlinDiscover{}
|
t.merlin = &merlinDiscover{}
|
||||||
if err := t.merlin.refresh(); err != nil {
|
t.ubios = &ubiosDiscover{}
|
||||||
ctrld.ProxyLogger.Load().Error().Err(err).Msg("could not init Merlin discover")
|
discovers := map[string]interface {
|
||||||
} else {
|
refresher
|
||||||
t.hostnameResolvers = append(t.hostnameResolvers, t.merlin)
|
HostnameResolver
|
||||||
t.refreshers = append(t.refreshers, t.merlin)
|
}{
|
||||||
|
"Merlin": t.merlin,
|
||||||
|
"Ubios": t.ubios,
|
||||||
|
}
|
||||||
|
for platform, discover := range discovers {
|
||||||
|
if err := discover.refresh(); err != nil {
|
||||||
|
ctrld.ProxyLogger.Load().Error().Err(err).Msgf("could not init %s discover", platform)
|
||||||
|
} else {
|
||||||
|
t.hostnameResolvers = append(t.hostnameResolvers, discover)
|
||||||
|
t.refreshers = append(t.refreshers, discover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hosts file mapping.
|
// Hosts file mapping.
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package clientinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Control-D-Inc/ctrld/internal/router"
|
||||||
|
"github.com/Control-D-Inc/ctrld/internal/router/ubios"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ubiosDiscover provides client discovery functionality on Ubios routers.
|
||||||
|
type ubiosDiscover struct {
|
||||||
|
hostname sync.Map // mac => hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
// refresh reloads unifi devices from database.
|
||||||
|
func (u *ubiosDiscover) refresh() error {
|
||||||
|
if router.Name() != ubios.Name {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return u.refreshDevices()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupHostnameByIP returns hostname for given IP.
|
||||||
|
func (u *ubiosDiscover) LookupHostnameByIP(ip string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupHostnameByMac returns unifi device custom hostname for the given MAC address.
|
||||||
|
func (u *ubiosDiscover) LookupHostnameByMac(mac string) string {
|
||||||
|
val, ok := u.hostname.Load(mac)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// refreshDevices updates unifi devices name from local mongodb.
|
||||||
|
func (u *ubiosDiscover) refreshDevices() error {
|
||||||
|
cmd := exec.Command("/usr/bin/mongo", "localhost:27117/ace", "--quiet", "--eval", `
|
||||||
|
DBQuery.shellBatchSize = 256;
|
||||||
|
db.user.find({name: {$exists: true, $ne: ""}}, {_id:0, mac:1, name:1});`)
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return u.storeDevices(bytes.NewReader(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// storeDevices saves unifi devices name for caching.
|
||||||
|
func (u *ubiosDiscover) storeDevices(r io.Reader) error {
|
||||||
|
decoder := json.NewDecoder(r)
|
||||||
|
device := struct {
|
||||||
|
MAC string
|
||||||
|
Name string
|
||||||
|
}{}
|
||||||
|
for {
|
||||||
|
err := decoder.Decode(&device)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mac := strings.ToLower(device.MAC)
|
||||||
|
u.hostname.Store(mac, normalizeHostname(device.Name))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns human-readable format of ubiosDiscover.
|
||||||
|
func (u *ubiosDiscover) String() string {
|
||||||
|
return "ubios"
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package clientinfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ubiosDiscover_storeDevices(t *testing.T) {
|
||||||
|
ud := &ubiosDiscover{}
|
||||||
|
r := strings.NewReader(`{ "mac": "00:00:00:00:00:01", "name": "device 1" }
|
||||||
|
{ "mac": "00:00:00:00:00:02", "name": "device 2" }
|
||||||
|
`)
|
||||||
|
if err := ud.storeDevices(r); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
mac string
|
||||||
|
hostname string
|
||||||
|
}{
|
||||||
|
{"device 1", "00:00:00:00:00:01", "device 1"},
|
||||||
|
{"device 2", "00:00:00:00:00:02", "device 2"},
|
||||||
|
{"non-existed", "00:00:00:00:00:03", ""},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if got := ud.LookupHostnameByMac(tc.mac); got != tc.hostname {
|
||||||
|
t.Errorf("hostname mismatched, want: %q, got: %q", tc.hostname, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for invalid input.
|
||||||
|
r = strings.NewReader(`{ "mac": "00:00:00:00:00:01", "name": "device 1"`)
|
||||||
|
if err := ud.storeDevices(r); err == nil {
|
||||||
|
t.Fatal("expected error, got nil")
|
||||||
|
} else {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user