Files
weave/weaver/main.go
T
Alex Bligh 12d88eac23 Add options to set ports on weaver command line
This commit adds two command line options, intended to allow multiple
instances of weave to run without container separation between them.

* -port=PORT makes weave bind to port PORT (an integer). Without the
  option, the default value (6783) is used.

* -httpaddr=ADDRESS makes weave bind its control interface to
  a different address. For instance "127.0.0.1:6784" can be used to
  bind to localhost only. An absent address element makes it bind to
  all interfaces. ":6784" is the default. An empty string
  can be used to disable the control interface.

Signed-off-by: Alex Bligh <alex@alex.org.uk>
2015-04-10 12:09:13 +01:00

222 lines
6.2 KiB
Go

package main
import (
"code.google.com/p/gopacket/layers"
"crypto/sha256"
"flag"
"fmt"
"github.com/davecheney/profile"
"github.com/gorilla/mux"
weavenet "github.com/weaveworks/weave/net"
weave "github.com/weaveworks/weave/router"
"io"
"log"
"net"
"net/http"
"os"
"os/signal"
"runtime"
"syscall"
)
var version = "(unreleased version)"
func main() {
log.SetPrefix(weave.Protocol + " ")
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
procs := runtime.NumCPU()
// packet sniffing can block an OS thread, so we need one thread
// for that plus at least one more.
if procs < 2 {
procs = 2
}
runtime.GOMAXPROCS(procs)
var (
justVersion bool
ifaceName string
routerName string
nickName string
password string
wait int
debug bool
prof string
peers []string
connLimit int
bufSz int
port int
httpAddr string
)
flag.BoolVar(&justVersion, "version", false, "print version and exit")
flag.StringVar(&ifaceName, "iface", "", "name of interface to capture/inject from (disabled if left blank)")
flag.StringVar(&routerName, "name", "", "name of router (defaults to MAC)")
flag.StringVar(&nickName, "nickname", "", "nickname of peer (defaults to hostname)")
flag.StringVar(&password, "password", "", "network password")
flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (defaults to 0, i.e. don't wait)")
flag.BoolVar(&debug, "debug", false, "enable debug logging")
flag.StringVar(&prof, "profile", "", "enable profiling and write profiles to given path")
flag.IntVar(&connLimit, "connlimit", 30, "connection limit (defaults to 30, set to 0 for unlimited)")
flag.IntVar(&bufSz, "bufsz", 8, "capture buffer size in MB (defaults to 8MB)")
flag.IntVar(&port, "port", weave.Port, fmt.Sprintf("router port (defaults to %d)", weave.Port))
flag.StringVar(&httpAddr, "httpaddr", fmt.Sprintf(":%d", weave.HTTPPort), fmt.Sprintf("address to bind HTTP interface to (defaults to :%d, set to \"\" to disable)", weave.HTTPPort))
flag.Parse()
peers = flag.Args()
if justVersion {
fmt.Printf("weave router %s\n", version)
os.Exit(0)
}
options := make(map[string]string)
flag.Visit(func(f *flag.Flag) {
value := f.Value.String()
if f.Name == "password" {
value = "<elided>"
}
options[f.Name] = value
})
log.Println("Command line options:", options)
log.Println("Command line peers:", peers)
var err error
var iface *net.Interface
if ifaceName != "" {
iface, err = weavenet.EnsureInterface(ifaceName, wait)
if err != nil {
log.Fatal(err)
}
}
if routerName == "" {
routerName = iface.HardwareAddr.String()
}
if nickName == "" {
nickName, err = os.Hostname()
if err != nil {
log.Fatal(err)
}
}
ourName, err := weave.PeerNameFromUserInput(routerName)
if err != nil {
log.Fatal(err)
}
if password == "" {
password = os.Getenv("WEAVE_PASSWORD")
}
var pwSlice []byte
if password == "" {
log.Println("Communication between peers is unencrypted.")
} else {
pwSlice = []byte(password)
log.Println("Communication between peers is encrypted.")
}
if prof != "" {
p := *profile.CPUProfile
p.ProfilePath = prof
defer profile.Start(&p).Stop()
}
router := weave.NewRouter(iface, ourName, nickName, pwSlice, connLimit, bufSz*1024*1024, logFrameFunc(debug), port)
log.Println("Our name is", router.Ourself.FullName())
router.Start()
initiateConnections(router, peers)
if httpAddr != "" {
go handleHTTP(router, httpAddr)
}
handleSignals(router)
}
func logFrameFunc(debug bool) func(string, []byte, *layers.Ethernet) {
if !debug {
return func(prefix string, frame []byte, eth *layers.Ethernet) {}
}
return func(prefix string, frame []byte, eth *layers.Ethernet) {
h := fmt.Sprintf("%x", sha256.Sum256(frame))
if eth == nil {
log.Println(prefix, len(frame), "bytes (", h, ")")
} else {
log.Println(prefix, len(frame), "bytes (", h, "):", eth.SrcMAC, "->", eth.DstMAC)
}
}
}
func initiateConnections(router *weave.Router, peers []string) {
for _, peer := range peers {
if addr, err := net.ResolveTCPAddr("tcp4", router.NormalisePeerAddr(peer)); err == nil {
router.ConnectionMaker.InitiateConnection(addr.String())
} else {
log.Fatal(err)
}
}
}
func handleHTTP(router *weave.Router, httpAddr string) {
encryption := "off"
if router.UsingPassword() {
encryption = "on"
}
muxRouter := mux.NewRouter()
muxRouter.Methods("GET").Path("/status").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, fmt.Sprintln("weave router", version))
io.WriteString(w, fmt.Sprintln("Encryption", encryption))
io.WriteString(w, router.Status())
})
muxRouter.Methods("GET").Path("/status-json").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json, _ := router.GenerateStatusJSON(version, encryption)
w.Write(json)
})
muxRouter.Methods("POST").Path("/connect").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
peer := r.FormValue("peer")
if addr, err := net.ResolveTCPAddr("tcp4", router.NormalisePeerAddr(peer)); err == nil {
router.ConnectionMaker.InitiateConnection(addr.String())
} else {
http.Error(w, fmt.Sprint("invalid peer address: ", err), http.StatusBadRequest)
}
})
muxRouter.Methods("POST").Path("/forget").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
peer := r.FormValue("peer")
if addr, err := net.ResolveTCPAddr("tcp4", router.NormalisePeerAddr(peer)); err == nil {
router.ConnectionMaker.ForgetConnection(addr.String())
} else {
http.Error(w, fmt.Sprint("invalid peer address: ", err), http.StatusBadRequest)
}
})
http.Handle("/", muxRouter)
err := http.ListenAndServe(httpAddr, nil)
if err != nil {
log.Fatal("Unable to create http listener: ", err)
}
}
func handleSignals(router *weave.Router) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGQUIT, syscall.SIGUSR1)
buf := make([]byte, 1<<20)
for {
sig := <-sigs
switch sig {
case syscall.SIGQUIT:
stacklen := runtime.Stack(buf, true)
log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
case syscall.SIGUSR1:
log.Printf("=== received SIGUSR1 ===\n*** status...\n%s\n*** end\n", router.Status())
}
}
}