blob: d67f1a7c217e4e415c3a3924719194b7218ea8e8 [file] [log] [blame]
package main
import (
"flag"
"io/ioutil"
"net"
"net/http"
"os"
"path/filepath"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/vlog"
"veyron.io/veyron/veyron/lib/netstate"
"veyron.io/veyron/veyron/lib/signals"
"veyron.io/veyron/veyron/profiles/roaming"
vflag "veyron.io/veyron/veyron/security/flag"
"veyron.io/veyron/veyron/services/mgmt/binary/impl"
)
const (
defaultDepth = 3
defaultRootPrefix = "veyron_binary_repository"
)
var (
name = flag.String("name", "", "name to mount the binary repository as")
root = flag.String("root", "", "root directory for the binary repository")
httpAddr = flag.String("http", ":0", "TCP address on which the HTTP server runs")
)
// toIPPort tries to swap in the 'best' accessible IP for the host part of the
// address, if the provided address has an unspecified IP.
func toIPPort(addr string) string {
host, port, err := net.SplitHostPort(addr)
if err != nil {
vlog.Errorf("SplitHostPort(%v) failed: %v", addr, err)
os.Exit(1)
}
ip := net.ParseIP(host)
if ip.IsUnspecified() {
host = "127.0.0.1"
ips, err := netstate.GetAccessibleIPs()
if err == nil {
if a, err := roaming.ListenSpec.AddressChooser("tcp", ips); err == nil && len(a) > 0 {
host = a[0].Address().String()
}
}
}
return net.JoinHostPort(host, port)
}
func main() {
runtime := rt.Init()
defer runtime.Cleanup()
if *root == "" {
var err error
if *root, err = ioutil.TempDir("", defaultRootPrefix); err != nil {
vlog.Errorf("TempDir() failed: %v\n", err)
return
}
path, perm := filepath.Join(*root, impl.VersionFile), os.FileMode(0600)
if err := ioutil.WriteFile(path, []byte(impl.Version), perm); err != nil {
vlog.Errorf("WriteFile(%v, %v, %v) failed: %v", path, impl.Version, perm, err)
return
}
} else {
_, err := os.Stat(*root)
switch {
case err == nil:
case os.IsNotExist(err):
perm := os.FileMode(0700)
if err := os.MkdirAll(*root, perm); err != nil {
vlog.Errorf("MkdirAll(%v, %v) failed: %v", *root, perm, err)
return
}
path, perm := filepath.Join(*root, impl.VersionFile), os.FileMode(0600)
if err := ioutil.WriteFile(path, []byte(impl.Version), perm); err != nil {
vlog.Errorf("WriteFile(%v, %v, %v) failed: %v", path, impl.Version, perm, err)
return
}
default:
vlog.Errorf("Stat(%v) failed: %v", *root, err)
return
}
}
vlog.Infof("Binary repository rooted at %v", *root)
state, err := impl.NewState(*root, defaultDepth)
if err != nil {
vlog.Errorf("NewState(%v, %v) failed: %v", *root, defaultDepth, err)
return
}
listener, err := net.Listen("tcp", *httpAddr)
if err != nil {
vlog.Errorf("Listen(%s) failed: %v", *httpAddr, err)
os.Exit(1)
}
vlog.Infof("Binary repository HTTP server at: %q", toIPPort(listener.Addr().String()))
go func() {
if err := http.Serve(listener, http.FileServer(impl.NewHTTPRoot(state))); err != nil {
vlog.Errorf("Serve() failed: %v", err)
os.Exit(1)
}
}()
server, err := runtime.NewServer()
if err != nil {
vlog.Errorf("NewServer() failed: %v", err)
return
}
defer server.Stop()
auth := vflag.NewAuthorizerOrDie()
endpoint, err := server.Listen(roaming.ListenSpec)
if err != nil {
vlog.Errorf("Listen(%s) failed: %v", roaming.ListenSpec, err)
return
}
if err := server.ServeDispatcher(*name, impl.NewDispatcher(state, auth)); err != nil {
vlog.Errorf("ServeDispatcher(%v) failed: %v", *name, err)
return
}
vlog.Infof("Binary repository running at endpoint=%q", endpoint)
// Wait until shutdown.
<-signals.ShutdownOnSignals()
}