Merge pull request #85 from neilalexander/yggdrasilctl

Human-readable formatting in yggdrasilctl
This commit is contained in:
Arceliar 2018-05-21 19:21:00 -05:00 committed by GitHub
commit b10ae51565
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 138 additions and 17 deletions

View File

@ -44,17 +44,20 @@ func (a *admin) init(c *Core, listenaddr string) {
a.core = c a.core = c
a.listenaddr = listenaddr a.listenaddr = listenaddr
a.addHandler("help", nil, func(in admin_info) (admin_info, error) { a.addHandler("help", nil, func(in admin_info) (admin_info, error) {
handlers := make(map[string][]string) handlers := make(map[string]interface{})
for _, handler := range a.handlers { for _, handler := range a.handlers {
handlers[handler.name] = handler.args handlers[handler.name] = admin_info{"fields": handler.args}
} }
return admin_info{"handlers": handlers}, nil return admin_info{"help": handlers}, nil
}) })
a.addHandler("dot", []string{}, func(in admin_info) (admin_info, error) { a.addHandler("dot", []string{}, func(in admin_info) (admin_info, error) {
return admin_info{"dot": string(a.getResponse_dot())}, nil return admin_info{"dot": string(a.getResponse_dot())}, nil
}) })
a.addHandler("getSelf", []string{}, func(in admin_info) (admin_info, error) { a.addHandler("getSelf", []string{}, func(in admin_info) (admin_info, error) {
return admin_info{"self": a.getData_getSelf().asMap()}, nil self := a.getData_getSelf().asMap()
ip := fmt.Sprint(self["ip"])
delete(self, "ip")
return admin_info{"self": admin_info{ip: self}}, nil
}) })
a.addHandler("getPeers", []string{}, func(in admin_info) (admin_info, error) { a.addHandler("getPeers", []string{}, func(in admin_info) (admin_info, error) {
sort := "ip" sort := "ip"
@ -133,14 +136,15 @@ func (a *admin) init(c *Core, listenaddr string) {
a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) { a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) {
defer func() { defer func() {
recover() recover()
r = admin_info{"name": "none"} r = admin_info{"none": admin_info{}}
e = nil e = nil
}() }()
return admin_info{ return admin_info{
"name": a.core.tun.iface.Name(), a.core.tun.iface.Name(): admin_info{
"tap_mode": a.core.tun.iface.IsTAP(), "tap_mode": a.core.tun.iface.IsTAP(),
"mtu": a.core.tun.mtu, "mtu": a.core.tun.mtu,
},
}, nil }, nil
}) })
a.addHandler("setTunTap", []string{"name", "[tap_mode]", "[mtu]"}, func(in admin_info) (admin_info, error) { a.addHandler("setTunTap", []string{"name", "[tap_mode]", "[mtu]"}, func(in admin_info) (admin_info, error) {
@ -162,9 +166,10 @@ func (a *admin) init(c *Core, listenaddr string) {
return admin_info{}, errors.New("Failed to configure adapter") return admin_info{}, errors.New("Failed to configure adapter")
} else { } else {
return admin_info{ return admin_info{
"name": a.core.tun.iface.Name(), a.core.tun.iface.Name(): admin_info{
"tap_mode": a.core.tun.iface.IsTAP(), "tap_mode": a.core.tun.iface.IsTAP(),
"mtu": ifmtu, "mtu": ifmtu,
},
}, nil }, nil
} }
}) })
@ -273,7 +278,7 @@ func (a *admin) handleRequest(conn net.Conn) {
if _, ok := recv[arg]; !ok { if _, ok := recv[arg]; !ok {
send = admin_info{ send = admin_info{
"status": "error", "status": "error",
"error": "Expected field missing", "error": "Expected field missing: " + arg,
"expecting": arg, "expecting": arg,
} }
break handlers break handlers
@ -432,7 +437,7 @@ func (a *admin) getData_getPeers() []admin_nodeInfo {
info := admin_nodeInfo{ info := admin_nodeInfo{
{"ip", net.IP(addr[:]).String()}, {"ip", net.IP(addr[:]).String()},
{"port", port}, {"port", port},
{"uptime", fmt.Sprint(time.Since(p.firstSeen))}, {"uptime", int(time.Since(p.firstSeen).Seconds())},
{"bytes_sent", atomic.LoadUint64(&p.bytesSent)}, {"bytes_sent", atomic.LoadUint64(&p.bytesSent)},
{"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)}, {"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)},
} }
@ -476,7 +481,7 @@ func (a *admin) getData_getDHT() []admin_nodeInfo {
{"coords", fmt.Sprint(v.coords)}, {"coords", fmt.Sprint(v.coords)},
{"bucket", i}, {"bucket", i},
{"peer_only", isPeer}, {"peer_only", isPeer},
{"last_seen", fmt.Sprint(now.Sub(v.recv))}, {"last_seen", int(now.Sub(v.recv).Seconds())},
} }
infos = append(infos, info) infos = append(infos, info)
} }

View File

@ -4,6 +4,7 @@ import "flag"
import "fmt" import "fmt"
import "strings" import "strings"
import "net" import "net"
import "sort"
import "encoding/json" import "encoding/json"
import "strconv" import "strconv"
import "os" import "os"
@ -12,11 +13,12 @@ type admin_info map[string]interface{}
func main() { func main() {
server := flag.String("endpoint", "localhost:9001", "Admin socket endpoint") server := flag.String("endpoint", "localhost:9001", "Admin socket endpoint")
injson := flag.Bool("json", false, "Output in JSON format")
flag.Parse() flag.Parse()
args := flag.Args() args := flag.Args()
if len(args) == 0 { if len(args) == 0 {
fmt.Println("usage:", os.Args[0], "[-endpoint=localhost:9001] command [key=value] [...]") fmt.Println("usage:", os.Args[0], "[-endpoint=localhost:9001] [-json] command [key=value] [...]")
fmt.Println("example:", os.Args[0], "getPeers") fmt.Println("example:", os.Args[0], "getPeers")
fmt.Println("example:", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false") fmt.Println("example:", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false")
fmt.Println("example:", os.Args[0], "-endpoint=localhost:9001 getDHT") fmt.Println("example:", os.Args[0], "-endpoint=localhost:9001 getDHT")
@ -58,19 +60,133 @@ func main() {
panic(err) panic(err)
} }
if err := decoder.Decode(&recv); err == nil { if err := decoder.Decode(&recv); err == nil {
if recv["status"] == "error" {
if err, ok := recv["error"]; ok {
fmt.Println("Error:", err)
} else {
fmt.Println("Unspecified error occured")
}
os.Exit(1)
}
if _, ok := recv["request"]; !ok { if _, ok := recv["request"]; !ok {
fmt.Println("Missing request") fmt.Println("Missing request in response (malformed response?)")
return return
} }
if _, ok := recv["response"]; !ok { if _, ok := recv["response"]; !ok {
fmt.Println("Missing response") fmt.Println("Missing response body (malformed response?)")
return return
} }
req := recv["request"].(map[string]interface{}) req := recv["request"].(map[string]interface{})
res := recv["response"].(map[string]interface{}) res := recv["response"].(map[string]interface{})
if *injson {
if json, err := json.MarshalIndent(res, "", " "); err == nil {
fmt.Println(string(json))
}
os.Exit(0)
}
switch req["request"] { switch req["request"] {
case "dot": case "dot":
fmt.Println(res["dot"]) fmt.Println(res["dot"])
case "help", "getPeers", "getSwitchPeers", "getDHT", "getSessions":
maxWidths := make(map[string]int)
var keyOrder []string
keysOrdered := false
for _, tlv := range res {
for slk, slv := range tlv.(map[string]interface{}) {
if !keysOrdered {
for k := range slv.(map[string]interface{}) {
keyOrder = append(keyOrder, fmt.Sprint(k))
}
sort.Strings(keyOrder)
keysOrdered = true
}
for k, v := range slv.(map[string]interface{}) {
if len(fmt.Sprint(slk)) > maxWidths["key"] {
maxWidths["key"] = len(fmt.Sprint(slk))
}
if len(fmt.Sprint(v)) > maxWidths[k] {
maxWidths[k] = len(fmt.Sprint(v))
if maxWidths[k] < len(k) {
maxWidths[k] = len(k)
}
}
}
}
if len(keyOrder) > 0 {
fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", "")
for _, v := range keyOrder {
fmt.Printf("%-"+fmt.Sprint(maxWidths[v])+"s ", v)
}
fmt.Println()
}
for slk, slv := range tlv.(map[string]interface{}) {
fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", slk)
for _, k := range keyOrder {
preformatted := slv.(map[string]interface{})[k]
var formatted string
switch k {
case "bytes_sent", "bytes_recvd":
formatted = fmt.Sprintf("%d", uint(preformatted.(float64)))
case "uptime", "last_seen":
seconds := uint(preformatted.(float64)) % 60
minutes := uint(preformatted.(float64)/60) % 60
hours := uint(preformatted.(float64) / 60 / 60)
formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
default:
formatted = fmt.Sprint(preformatted)
}
fmt.Printf("%-"+fmt.Sprint(maxWidths[k])+"s ", formatted)
}
fmt.Println()
}
}
case "getTunTap", "setTunTap":
for k, v := range res {
fmt.Println("Interface name:", k)
if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok {
fmt.Println("Interface MTU:", mtu)
}
if tap_mode, ok := v.(map[string]interface{})["tap_mode"].(bool); ok {
fmt.Println("TAP mode:", tap_mode)
}
}
case "addPeer", "removePeer", "addAllowedBoxPub", "removeAllowedBoxPub":
if _, ok := res["added"]; ok {
for _, v := range res["added"].([]interface{}) {
fmt.Println("Added:", fmt.Sprint(v))
}
}
if _, ok := res["not_added"]; ok {
for _, v := range res["not_added"].([]interface{}) {
fmt.Println("Not added:", fmt.Sprint(v))
}
}
if _, ok := res["removed"]; ok {
for _, v := range res["removed"].([]interface{}) {
fmt.Println("Removed:", fmt.Sprint(v))
}
}
if _, ok := res["not_removed"]; ok {
for _, v := range res["not_removed"].([]interface{}) {
fmt.Println("Not removed:", fmt.Sprint(v))
}
}
case "getAllowedBoxPubs":
if _, ok := res["allowed_box_pubs"]; !ok {
fmt.Println("All connections are allowed")
} else if res["allowed_box_pubs"] == nil {
fmt.Println("All connections are allowed")
} else {
fmt.Println("Connections are allowed only from the following public box keys:")
for _, v := range res["allowed_box_pubs"].([]interface{}) {
fmt.Println("-", v)
}
}
default: default:
if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil { if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil {
fmt.Println(string(json)) fmt.Println(string(json))