Switch to cobra for the CLI
This commit is contained in:
parent
f4650213b8
commit
cbb5f2e59b
|
@ -8,5 +8,4 @@ install:
|
|||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- ./.test-coverage
|
||||
- go install github.com/FreifunkBremen/yanic/cmd/yanic
|
||||
- go install github.com/FreifunkBremen/yanic/cmd/yanic-query
|
||||
- go install github.com/FreifunkBremen/yanic
|
||||
|
|
71
README.md
71
README.md
|
@ -28,16 +28,77 @@ Recently seen nodes that does not reply are requested via a unicast message.
|
|||
* [Mobi](https://www.gitbook.com/download/mobi/book/freifunkbremen/yanic)
|
||||
* [ePUB](https://www.gitbook.com/download/epub/book/freifunkbremen/yanic)
|
||||
|
||||
## Configuration
|
||||
Read comments in [config_example.toml](config_example.toml) for more information.
|
||||
|
||||
## Quick startup
|
||||
## Running
|
||||
|
||||
Yanic provides several commands:
|
||||
|
||||
### Usage
|
||||
|
||||
Run Yanic without any arguments to get the usage information:
|
||||
|
||||
```
|
||||
Usage of ./yanic:
|
||||
-config path/to/config.toml
|
||||
Usage:
|
||||
yanic [command]
|
||||
|
||||
Available Commands:
|
||||
help Help about any command
|
||||
import Imports global statistics from the given RRD files, requires InfluxDB
|
||||
query Sends a query on the interface to the destination and waits for a response
|
||||
serve Runs the yanic server
|
||||
|
||||
Flags:
|
||||
-h, --help help for yanic
|
||||
--timestamps Enables timestamps for log output
|
||||
|
||||
Use "yanic [command] --help" for more information about a command.
|
||||
```
|
||||
### Configuration
|
||||
Read comments in [config_example.toml](config_example.toml) for more information.
|
||||
|
||||
#### Serve
|
||||
|
||||
```
|
||||
Usage:
|
||||
yanic serve [flags]
|
||||
|
||||
Examples:
|
||||
yanic serve -config /etc/yanic.toml
|
||||
|
||||
Flags:
|
||||
-c, --config string Path to configuration file (default "config.toml")
|
||||
-h, --help help for serve
|
||||
```
|
||||
|
||||
#### Import
|
||||
|
||||
```
|
||||
Usage:
|
||||
yanic import <file.rrd> [flags]
|
||||
|
||||
Examples:
|
||||
yanic import -config /etc/yanic.toml olddata.rrd
|
||||
|
||||
Flags:
|
||||
-c, --config string Path to configuration file (default "config.toml")
|
||||
-h, --help help for import
|
||||
```
|
||||
|
||||
|
||||
#### Query
|
||||
|
||||
```
|
||||
Usage:
|
||||
yanic query <interface> <destination> [flags]
|
||||
|
||||
Examples:
|
||||
yanic query wlan0 "[fe80::eade:27ff:dead:beef%wlp4s0]:1001"
|
||||
|
||||
Flags:
|
||||
-h, --help help for query
|
||||
--wait int Seconds to wait for a response (default 1)
|
||||
```
|
||||
|
||||
|
||||
### Live
|
||||
* [meshviewer](https://map.bremen.freifunk.net) **Freifunk Bremen** with a patch to show state-version of `nodes.json`
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/database"
|
||||
"github.com/FreifunkBremen/yanic/respond"
|
||||
"github.com/FreifunkBremen/yanic/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
configPath string
|
||||
collector *respond.Collector
|
||||
connections database.Connection
|
||||
nodes *runtime.Nodes
|
||||
)
|
||||
|
||||
func loadConfig() *runtime.Config {
|
||||
config, err := runtime.ReadConfigFile(configPath)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "unable to load config file:", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
return config
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/database"
|
||||
"github.com/FreifunkBremen/yanic/database/all"
|
||||
"github.com/FreifunkBremen/yanic/rrd"
|
||||
"github.com/FreifunkBremen/yanic/runtime"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// importCmd represents the import command
|
||||
var importCmd = &cobra.Command{
|
||||
Use: "import <file.rrd>",
|
||||
Short: "Imports global statistics from the given RRD files, requires InfluxDB",
|
||||
Example: "yanic import -config /etc/yanic.toml olddata.rrd",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
path := args[0]
|
||||
config := loadConfig()
|
||||
|
||||
connections, err := all.Connect(config.Database.Connection)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
database.Start(connections, config)
|
||||
defer database.Close(connections)
|
||||
|
||||
log.Println("importing RRD from", path)
|
||||
|
||||
for ds := range rrd.Read(path) {
|
||||
connections.InsertGlobals(
|
||||
&runtime.GlobalStats{
|
||||
Nodes: uint32(ds.Nodes),
|
||||
Clients: uint32(ds.Clients),
|
||||
},
|
||||
ds.Time,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(importCmd)
|
||||
importCmd.Flags().StringVarP(&configPath, "config", "c", "config.toml", "Path to configuration file")
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/respond"
|
||||
"github.com/FreifunkBremen/yanic/runtime"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var wait int
|
||||
|
||||
// queryCmd represents the query command
|
||||
var queryCmd = &cobra.Command{
|
||||
Use: "query <interface> <destination>",
|
||||
Short: "Sends a query on the interface to the destination and waits for a response",
|
||||
Example: `yanic query wlan0 "[fe80::eade:27ff:dead:beef%wlp4s0]:1001"`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
iface := args[0]
|
||||
dstAddress := args[1]
|
||||
|
||||
log.Printf("Sending request address=%s iface=%s", dstAddress, iface)
|
||||
|
||||
nodes := runtime.NewNodes(&runtime.Config{})
|
||||
|
||||
collector := respond.NewCollector(nil, nodes, iface, 0)
|
||||
defer collector.Close()
|
||||
collector.SendPacket(net.ParseIP(dstAddress))
|
||||
|
||||
time.Sleep(time.Second * time.Duration(wait))
|
||||
|
||||
for id, data := range nodes.List {
|
||||
log.Printf("%s: %+v", id, data)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(queryCmd)
|
||||
queryCmd.Flags().IntVar(&wait, "wait", 1, "Seconds to wait for a response")
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
timestamps bool
|
||||
)
|
||||
|
||||
// RootCmd represents the base command when called without any subcommands
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: "yanic",
|
||||
Short: "Yet another node info collector",
|
||||
Long: `A respondd client that fetches, stores and publishes information about a Freifunk network.`,
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
if err := RootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
RootCmd.PersistentFlags().BoolVar(×tamps, "timestamps", false, "Enables timestamps for log output")
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if timestamps {
|
||||
log.SetFlags(log.Lshortfile)
|
||||
} else {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/database"
|
||||
"github.com/FreifunkBremen/yanic/database/all"
|
||||
"github.com/FreifunkBremen/yanic/meshviewer"
|
||||
"github.com/FreifunkBremen/yanic/respond"
|
||||
"github.com/FreifunkBremen/yanic/runtime"
|
||||
"github.com/FreifunkBremen/yanic/webserver"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// serveCmd represents the serve command
|
||||
var serveCmd = &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "Runs the yanic server",
|
||||
Example: "yanic serve -config /etc/yanic.toml",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
config := loadConfig()
|
||||
|
||||
connections, err := all.Connect(config.Database.Connection)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
database.Start(connections, config)
|
||||
defer database.Close(connections)
|
||||
|
||||
nodes = runtime.NewNodes(config)
|
||||
nodes.Start()
|
||||
meshviewer.Start(config, nodes)
|
||||
|
||||
if config.Webserver.Enable {
|
||||
log.Println("starting webserver on", config.Webserver.Bind)
|
||||
srv := webserver.New(config.Webserver.Bind, config.Webserver.Webroot)
|
||||
go srv.Close()
|
||||
}
|
||||
|
||||
if config.Respondd.Enable {
|
||||
// Delaying startup to start at a multiple of `duration` since the zero time.
|
||||
if duration := config.Respondd.Synchronize.Duration; duration > 0 {
|
||||
now := time.Now()
|
||||
delay := duration - now.Sub(now.Truncate(duration))
|
||||
log.Printf("delaying %0.1f seconds", delay.Seconds())
|
||||
time.Sleep(delay)
|
||||
}
|
||||
|
||||
collector = respond.NewCollector(connections, nodes, config.Respondd.Interface, config.Respondd.Port)
|
||||
collector.Start(config.Respondd.CollectInterval.Duration)
|
||||
defer collector.Close()
|
||||
}
|
||||
|
||||
// Wait for INT/TERM
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
sig := <-sigs
|
||||
log.Println("received", sig)
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(serveCmd)
|
||||
serveCmd.Flags().StringVarP(&configPath, "config", "c", "config.toml", "Path to configuration file")
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/respond"
|
||||
"github.com/FreifunkBremen/yanic/runtime"
|
||||
)
|
||||
|
||||
// Usage: yanic-query wlp4s0 "[fe80::eade:27ff:dead:beef%wlp4s0]:1001"
|
||||
func main() {
|
||||
iface := os.Args[1]
|
||||
dstAddress := os.Args[2]
|
||||
|
||||
log.Printf("Sending request address=%s iface=%s", dstAddress, iface)
|
||||
|
||||
nodes := runtime.NewNodes(&runtime.Config{})
|
||||
|
||||
collector := respond.NewCollector(nil, nodes, iface, 0)
|
||||
collector.SendPacket(net.ParseIP(dstAddress))
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
for id, data := range nodes.List {
|
||||
log.Printf("%s: %+v", id, data)
|
||||
}
|
||||
|
||||
collector.Close()
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/FreifunkBremen/yanic/database"
|
||||
"github.com/FreifunkBremen/yanic/database/all"
|
||||
"github.com/FreifunkBremen/yanic/meshviewer"
|
||||
"github.com/FreifunkBremen/yanic/respond"
|
||||
"github.com/FreifunkBremen/yanic/rrd"
|
||||
"github.com/FreifunkBremen/yanic/runtime"
|
||||
"github.com/FreifunkBremen/yanic/webserver"
|
||||
)
|
||||
|
||||
var (
|
||||
configFile string
|
||||
config *runtime.Config
|
||||
collector *respond.Collector
|
||||
connections database.Connection
|
||||
nodes *runtime.Nodes
|
||||
)
|
||||
|
||||
func main() {
|
||||
var importPath string
|
||||
var timestamps bool
|
||||
flag.StringVar(&importPath, "import", "", "import global statistics from the given RRD file, requires influxdb")
|
||||
flag.StringVar(&configFile, "config", "config.toml", "path of configuration file (default:config.yaml)")
|
||||
flag.BoolVar(×tamps, "timestamps", true, "print timestamps in output")
|
||||
flag.Parse()
|
||||
|
||||
if !timestamps {
|
||||
log.SetFlags(0)
|
||||
}
|
||||
log.Println("Yanic say hello")
|
||||
|
||||
config, err := runtime.ReadConfigFile(configFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
nodes = runtime.NewNodes(config)
|
||||
|
||||
connections, err = all.Connect(config.Database.Connection)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
database.Start(connections, config)
|
||||
defer database.Close(connections)
|
||||
|
||||
if connections != nil && importPath != "" {
|
||||
importRRD(importPath)
|
||||
return
|
||||
}
|
||||
|
||||
nodes.Start()
|
||||
meshviewer.Start(config, nodes)
|
||||
|
||||
if config.Webserver.Enable {
|
||||
log.Println("starting webserver on", config.Webserver.Bind)
|
||||
srv := webserver.New(config.Webserver.Bind, config.Webserver.Webroot)
|
||||
go srv.Close()
|
||||
}
|
||||
|
||||
if config.Respondd.Enable {
|
||||
// Delaying startup to start at a multiple of `duration` since the zero time.
|
||||
if duration := config.Respondd.Synchronize.Duration; duration > 0 {
|
||||
now := time.Now()
|
||||
delay := duration - now.Sub(now.Truncate(duration))
|
||||
log.Printf("delaying %0.1f seconds", delay.Seconds())
|
||||
time.Sleep(delay)
|
||||
}
|
||||
|
||||
collector = respond.NewCollector(connections, nodes, config.Respondd.Interface, config.Respondd.Port)
|
||||
collector.Start(config.Respondd.CollectInterval.Duration)
|
||||
defer collector.Close()
|
||||
}
|
||||
|
||||
// Wait for INT/TERM
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
sig := <-sigs
|
||||
log.Println("received", sig)
|
||||
}
|
||||
|
||||
func importRRD(path string) {
|
||||
log.Println("importing RRD from", path)
|
||||
for ds := range rrd.Read(path) {
|
||||
connections.InsertGlobals(
|
||||
&runtime.GlobalStats{
|
||||
Nodes: uint32(ds.Nodes),
|
||||
Clients: uint32(ds.Clients),
|
||||
},
|
||||
ds.Time,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ Description=yanic
|
|||
[Service]
|
||||
Type=simple
|
||||
User=yanic
|
||||
ExecStart=/opt/go/bin/yanic -config /etc/yanic.conf
|
||||
ExecStart=/opt/go/bin/yanic serve -config /etc/yanic.conf
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
Environment=PATH=/usr/bin:/usr/local/bin
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "github.com/FreifunkBremen/yanic/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
|
@ -45,12 +45,12 @@ func ReadConfigFile(path string) (config *Config, err error) {
|
|||
|
||||
file, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = toml.Unmarshal(file, config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue