freifunkmanager/runtime/node.go

160 lines
5.2 KiB
Go

package runtime
import (
"bytes"
"fmt"
"net"
log "github.com/sirupsen/logrus"
yanicData "github.com/FreifunkBremen/yanic/data"
"github.com/FreifunkBremen/yanic/lib/jsontime"
yanicRuntime "github.com/FreifunkBremen/yanic/runtime"
"github.com/FreifunkBremen/freifunkmanager/ssh"
)
const (
SSHUpdateHostname = "uci set system.@system[0].hostname='%s'; uci set wireless.priv_radio0.ssid=\"offline-$(uci get system.@system[0].hostname)\"; uci set wireless.priv_radio1.ssid=\"offline-$(uci get system.@system[0].hostname)\"; uci commit; echo $(uci get system.@system[0].hostname) > /proc/sys/kernel/hostname; wifi"
SSHUpdateOwner = "uci set gluon-node-info.@owner[0].contact='%s';uci commit gluon-node-info;"
SSHUpdateLocation = "uci set gluon-node-info.@location[0].latitude='%f';uci set gluon-node-info.@location[0].longitude='%f';uci set gluon-node-info.@location[0].share_location=1;uci commit gluon-node-info;"
SSHUpdateWifiFreq24 = "if [ \"$(uci get wireless.radio0.hwmode | grep -c g)\" -ne 0 ]; then uci set wireless.radio0.channel='%d'; uci set wireless.radio0.txpower='%d'; elif [ \"$(uci get wireless.radio1.hwmode | grep -c g)\" -ne 0 ]; then uci set wireless.radio1.channel='%d'; uci set wireless.radio1.txpower='%d'; fi;"
SSHUpdateWifiFreq5 = "if [ \"$(uci get wireless.radio0.hwmode | grep -c a)\" -ne 0 ]; then uci set wireless.radio0.channel='%d'; uci set wireless.radio0.txpower='%d'; elif [ \"$(uci get wireless.radio1.hwmode | grep -c a)\" -ne 0 ]; then uci set wireless.radio1.channel='%d'; uci set wireless.radio1.txpower='%d'; fi;"
)
type Node struct {
Lastseen jsontime.Time `json:"lastseen"`
NodeID string `json:"node_id"`
Hostname string `json:"hostname"`
Location yanicData.Location `json:"location"`
Wireless yanicData.Wireless `json:"wireless"`
Owner string `json:"owner"`
Address net.IP `json:"-"`
Stats struct {
Wireless yanicData.WirelessStatistics `json:"wireless"`
Clients yanicData.Clients `json:"clients"`
} `json:"statistics"`
}
func NewNode(nodeOrigin *yanicRuntime.Node) *Node {
if nodeinfo := nodeOrigin.Nodeinfo; nodeinfo != nil {
node := &Node{
Hostname: nodeinfo.Hostname,
NodeID: nodeinfo.NodeID,
}
for _, ip := range nodeinfo.Network.Addresses {
ipAddr := net.ParseIP(ip)
if node.Address == nil || ipAddr.IsGlobalUnicast() {
node.Address = ipAddr
}
}
if owner := nodeinfo.Owner; owner != nil {
node.Owner = owner.Contact
}
if location := nodeinfo.Location; location != nil {
node.Location = *location
}
if wireless := nodeinfo.Wireless; wireless != nil {
node.Wireless = *wireless
}
if stats := nodeOrigin.Statistics; stats != nil {
node.Stats.Clients = stats.Clients
node.Stats.Wireless = stats.Wireless
}
return node
}
return nil
}
func (n *Node) SSHUpdate(ssh *ssh.Manager, iface string, oldnode *Node) {
addr := n.GetAddress(iface)
if oldnode == nil || n.Hostname != oldnode.Hostname {
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateHostname, n.Hostname))
}
if oldnode == nil || n.Owner != oldnode.Owner {
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateOwner, n.Owner))
}
if oldnode == nil || !locationEqual(n.Location, oldnode.Location) {
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateLocation, n.Location.Latitude, n.Location.Longitude))
}
if oldnode == nil || !wirelessEqual(n.Wireless, oldnode.Wireless) {
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateWifiFreq24, n.Wireless.Channel24, n.Wireless.TxPower24, n.Wireless.Channel24, n.Wireless.TxPower24))
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateWifiFreq5, n.Wireless.Channel5, n.Wireless.TxPower5, n.Wireless.Channel5, n.Wireless.TxPower5))
ssh.ExecuteOn(addr, "wifi")
// send warning for running wifi, because it kicks clients from node
log.Warn("[cmd] wifi ", n.NodeID)
}
oldnode = n
}
func (n *Node) GetAddress(iface string) net.TCPAddr {
return net.TCPAddr{IP: n.Address, Port: 22, Zone: iface}
}
func (n *Node) Update(node *yanicRuntime.Node) {
if nodeinfo := node.Nodeinfo; nodeinfo != nil {
n.Hostname = nodeinfo.Hostname
n.NodeID = nodeinfo.NodeID
n.Address = node.Address.IP
if owner := nodeinfo.Owner; owner != nil {
n.Owner = owner.Contact
}
if location := nodeinfo.Location; location != nil {
n.Location = *location
}
if wireless := nodeinfo.Wireless; wireless != nil {
n.Wireless = *wireless
}
}
}
func (n *Node) IsEqual(node *Node) bool {
if n.NodeID != node.NodeID {
return false
}
if !bytes.Equal(n.Address, node.Address) {
return false
}
if n.Hostname != node.Hostname {
return false
}
if n.Owner != node.Owner {
return false
}
if !locationEqual(n.Location, node.Location) {
return false
}
if !wirelessEqual(n.Wireless, node.Wireless) {
return false
}
return true
}
func locationEqual(a, b yanicData.Location) bool {
if a.Latitude != b.Latitude {
return false
}
if a.Longitude != b.Longitude {
return false
}
if a.Altitude != b.Altitude {
return false
}
return true
}
func wirelessEqual(a, b yanicData.Wireless) bool {
if a.Channel24 != b.Channel24 {
return false
}
if a.Channel5 != b.Channel5 {
return false
}
if a.TxPower24 != b.TxPower24 {
return false
}
if a.TxPower5 != b.TxPower5 {
return false
}
return true
}