add micro controller for clients

This commit is contained in:
Martin Geno 2017-07-08 18:42:03 +02:00
parent c28a14010d
commit c704b08d5c
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
3 changed files with 148 additions and 5 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/genofire/golang-lib/worker" "github.com/genofire/golang-lib/worker"
configPackage "github.com/FreifunkBremen/freifunkmanager/config" configPackage "github.com/FreifunkBremen/freifunkmanager/config"
wifiController "github.com/FreifunkBremen/freifunkmanager/controller"
"github.com/FreifunkBremen/freifunkmanager/runtime" "github.com/FreifunkBremen/freifunkmanager/runtime"
"github.com/FreifunkBremen/freifunkmanager/ssh" "github.com/FreifunkBremen/freifunkmanager/ssh"
"github.com/FreifunkBremen/freifunkmanager/websocket" "github.com/FreifunkBremen/freifunkmanager/websocket"
@ -43,14 +44,16 @@ func main() {
commands = runtime.NewCommands(sshmanager) commands = runtime.NewCommands(sshmanager)
// nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater) // nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater)
nodesSaveWorker := worker.NewWorker(time.Duration(3)*time.Second, nodes.Saver) nodesSaveWorker := worker.NewWorker(time.Duration(3)*time.Second, nodes.Saver)
controller := wifiController.NewController(sshmanager)
// go nodesUpdateWorker.Start() // go nodesUpdateWorker.Start()
go nodesSaveWorker.Start() go nodesSaveWorker.Start()
go controller.Start()
websocket.Start(nodes, commands) websocket.Start(nodes, commands)
if config.Yanic.Enable { if config.Yanic.Enable {
yanicDialer := yanic.Dial(config.Yanic.Type, config.Yanic.Address) yanicDialer = yanic.Dial(config.Yanic.Type, config.Yanic.Address)
yanicDialer.NodeHandler = nodes.LearnNode yanicDialer.NodeHandler = nodes.LearnNode
yanicDialer.GlobalsHandler = func(data *runtimeYanic.GlobalStats) { yanicDialer.GlobalsHandler = func(data *runtimeYanic.GlobalStats) {
stats = data stats = data
@ -90,6 +93,7 @@ func main() {
// Stop services // Stop services
websocket.Close() websocket.Close()
srv.Close() srv.Close()
controller.Close()
if config.Yanic.Enable { if config.Yanic.Enable {
yanicDialer.Close() yanicDialer.Close()
} }

139
controller/main.go Normal file
View File

@ -0,0 +1,139 @@
package controller
import (
"fmt"
"net"
"strconv"
"strings"
"sync"
"time"
"github.com/genofire/golang-lib/log"
"github.com/FreifunkBremen/freifunkmanager/ssh"
)
const (
maxDB = 80
)
type Controller struct {
sshMgmt *ssh.Manager
no24Ghz map[string]bool
node map[string]map[string]time.Time
quit chan struct{}
sync.Mutex
}
func NewController(ssh *ssh.Manager) *Controller {
return &Controller{
sshMgmt: ssh,
quit: make(chan struct{}),
}
}
func (c *Controller) Start() {
ticker := time.NewTicker(time.Second)
for {
select {
case <-ticker.C:
c.tick()
case <-c.quit:
ticker.Stop()
return
}
}
}
func (c *Controller) Close() {
close(c.quit)
}
func (c *Controller) tick() {
c.sshMgmt.RunEverywhere("if [ \"$(uci get wireless.radio0.hwmode | grep -c a)\" -ne 0 ]; then echo \"radio0\"; elif [ \"$(uci get wireless.radio1.hwmode | grep -c a)\" -ne 0 ]; then echo \"radio1\"; fi", ssh.SSHResultToStringHandler(func(ip string, iface string, err error) {
if err != nil {
return
}
addr := net.TCPAddr{IP: net.ParseIP(ip), Port: 22}
result, err := c.sshMgmt.RunOn(addr, fmt.Sprintf("iwinfo %s assoclist | grep SNR", iface))
if err != nil {
return
}
for _, line := range strings.Split(result, "\n") {
parts := strings.Fields(line)
mac := parts[0]
db, err := strconv.Atoi(parts[1])
if err != nil {
return
}
c.no24Ghz[mac] = true
if db > maxDB {
node, ok := c.node[ip]
if !ok {
node = make(map[string]time.Time)
c.node[ip] = node
}
now := time.Now()
if last, ok := node[mac]; ok && last.After(now.Add(-3*time.Second)) {
continue
}
log.Log.Info("force roamed %s from %s", mac, addr)
cmd := fmt.Sprintf("ubus call hostapd.%s del_client '{\"addr\":\"%s\", \"reason\":1, \"deauth\":true, \"ban_time\":1000}'", iface, mac)
c.sshMgmt.ExecuteOn(addr, cmd)
node[mac] = now
}
}
}))
c.sshMgmt.RunEverywhere("if [ \"$(uci get wireless.radio0.hwmode | grep -c g)\" -ne 0 ]; then echo \"radio0\"; elif [ \"$(uci get wireless.radio1.hwmode | grep -c g)\" -ne 0 ]; then echo \"radio1\"; fi", ssh.SSHResultToStringHandler(func(ip string, iface string, err error) {
if err != nil {
return
}
addr := net.TCPAddr{IP: net.ParseIP(ip), Port: 22}
result, err := c.sshMgmt.RunOn(addr, fmt.Sprintf("iwinfo %s assoclist | grep SNR", iface))
if err != nil {
return
}
for _, line := range strings.Split(result, "\n") {
parts := strings.Fields(line)
mac := parts[0]
db, err := strconv.Atoi(parts[1])
if err != nil {
return
}
cmd := fmt.Sprintf("ubus call hostapd.%s del_client '{\"addr\":\"%s\", \"reason\":1, \"deauth\":true, \"ban_time\":1000}'", iface, mac)
if c.no24Ghz[mac] {
log.Log.Info("kicked becouse it use 2.4 Ghz %s from %s", mac, addr)
c.sshMgmt.ExecuteOn(addr, cmd)
}
if db > maxDB {
node, ok := c.node[ip]
if !ok {
node = make(map[string]time.Time)
c.node[ip] = node
}
now := time.Now()
if last, ok := node[mac]; ok && last.After(now.Add(-3*time.Second)) {
continue
}
log.Log.Info("force roamed %s from %s", mac, addr)
c.sshMgmt.ExecuteOn(addr, cmd)
node[mac] = now
}
}
}))
}

View File

@ -8,7 +8,7 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
type SSHResultHandler func(string, error) type SSHResultHandler func(string, string, error)
func SSHResultToString(result string) string { func SSHResultToString(result string) string {
if len(result) > 0 { if len(result) > 0 {
@ -18,15 +18,15 @@ func SSHResultToString(result string) string {
} }
func SSHResultToStringHandler(handler SSHResultHandler) SSHResultHandler { func SSHResultToStringHandler(handler SSHResultHandler) SSHResultHandler {
return func(result string, err error) { return func(addr string, result string, err error) {
handler(SSHResultToString(result), err) handler(addr, SSHResultToString(result), err)
} }
} }
func (m *Manager) RunEverywhere(cmd string, handler SSHResultHandler) { func (m *Manager) RunEverywhere(cmd string, handler SSHResultHandler) {
for host, client := range m.clients { for host, client := range m.clients {
result, err := m.run(host, client, cmd) result, err := m.run(host, client, cmd)
handler(result, err) handler(host, result, err)
} }
} }