Merge branch 'Xe/fix/update-ln' of xena/route into master

This commit is contained in:
Cadey Ratio 2017-10-01 11:11:48 -04:00 committed by Gogs
commit 334f483574
24 changed files with 538 additions and 128 deletions

View File

@ -31,6 +31,7 @@ var allScopes = []string{
"token:get", "token:getall", "token:put", "token:delete", "token:deactivate",
"route:get", "route:getall", "route:put", "route:delete",
"connect",
"admin",
}
var whoami string
@ -123,10 +124,21 @@ func handle(w http.ResponseWriter, r *http.Request) {
func main() {
cmdline := kingpin.MustParse(app.Parse(os.Args[1:]))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
retry_netrc:
n, err := netrc.Parse(*netrcPath)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "netrc.Parse"})
_, err := os.Stat(*netrcPath)
if err == os.ErrNotExist {
fout, err := os.Create(*netrcPath)
if err != nil {
ln.FatalErr(ctx, err, ln.Action("creating netrc"), ln.F{"path": *netrcPath})
}
fout.Close()
goto retry_netrc
}
}
_ = n
@ -134,30 +146,35 @@ func main() {
case "test-server":
http.HandleFunc("/", handle)
ln.Fatal(ln.F{"err": http.ListenAndServe(*testServerAddr, nil), "action": "test_server"})
ln.FatalErr(ctx, http.ListenAndServe(*testServerAddr, nil), ln.Action("test server listenAndServe"))
return
case "generate-key":
key, err := routecrypto.GenerateKey()
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "routecrypto.GenerateKey"})
ln.FatalErr(ctx, err, ln.Action("generating encryption key"))
}
fmt.Println("Your key is:", routecrypto.ShowKey(key))
return
case "token generate-root":
key, err := routecrypto.ParseKey(*tokenGenerateKey)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "routecrypto.ParseKey"})
ln.FatalErr(ctx, err, ln.Action("parsing encryption key"))
}
db, err := database.NewBoltStorage(*tokenGenerateDatabasePath, key)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "database.NewBoltStorage"})
ln.FatalErr(ctx, err, ln.Action("opening routed database"))
}
tBody := uuid.New()
_, err = db.PutToken(context.Background(), tBody, *tokenGenerateUsername, *tokenGenerateScopes)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "db.PutToken"})
ln.FatalErr(ctx, err, ln.Action("add newly created token to database"))
}
defer db.Close()
@ -166,7 +183,7 @@ func main() {
n.AddMachine(*grpcServer, *tokenGenerateUsername, tBody)
err = n.Save()
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "n.Save"})
ln.FatalErr(ctx, err, ln.Action("add machine to netrc"))
}
return
@ -182,7 +199,7 @@ func main() {
grpc.WithTransportCredentials(connCreds),
grpc.WithPerRPCCredentials(creds))
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "grpc.Dial"})
ln.FatalErr(ctx, err, ln.Action("dialing grpc server"), ln.F{"hostname": *grpcServer})
}
rc := proto.NewRoutesClient(conn)
@ -195,19 +212,21 @@ func main() {
switch cmdline {
case "route create":
idr, err := rc.Put(context.Background(), &proto.Route{Host: *routesCreateDomain})
idr, err := rc.Put(ctx, &proto.Route{Host: *routesCreateDomain})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "rc.Put"})
ln.FatalErr(ctx, err, ln.Action("create new route"))
}
fmt.Println(idr.Id)
fmt.Println("created route with id " + idr.Id)
return
case "route inspect":
r, err := rc.Get(context.Background(), &proto.GetRouteRequest{
Host: *routesCreateDomain,
})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "rc.Get"})
ln.FatalErr(ctx, err, ln.Action("get single route"), ln.F{"domain": *routesCreateDomain})
}
json.NewEncoder(os.Stdout).Encode(r)
@ -218,7 +237,7 @@ func main() {
case "route list":
rts, err := rc.GetAll(context.Background(), &proto.Nil{})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "rc.GetAll"})
ln.FatalErr(ctx, err, ln.Action("get all routes"))
}
table := tablewriter.NewWriter(os.Stdout)
@ -235,16 +254,18 @@ func main() {
case "route rm":
_, err := rc.Delete(context.Background(), &proto.Route{Id: *routesRmID})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "rc.Delete"})
ln.FatalErr(ctx, err, ln.Action("remove single route"), ln.F{"id": *routesRmID})
}
return
case "backend list":
bkds, err := bc.List(context.Background(), &proto.BackendSelector{
Domain: *backendListDomain,
User: *backendListUser,
})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "list backends"})
ln.FatalErr(ctx, err, ln.Action("list backends"))
}
table := tablewriter.NewWriter(os.Stdout)
@ -256,12 +277,51 @@ func main() {
table.Render()
return
case "backend kill":
_, err := bc.Kill(context.Background(), &proto.BackendID{Id: *backendKillID})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "attempt to kill backend", "backend_id": *backendKillID})
ln.FatalErr(ctx, err, ln.Action("attempt to kill backend"), ln.F{"backend_id": *backendKillID})
}
fmt.Println("killed backend " + *backendKillID)
return
case "token list":
lis, err := tc.GetAll(ctx, &proto.Nil{})
if err != nil {
ln.FatalErr(ctx, err, ln.Action("get all tokens"))
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"ID", "Active", "Scopes"})
for _, tkn := range lis.Tokens {
table.Append([]string{tkn.Id, fmt.Sprint(tkn.Active), fmt.Sprint(tkn.Scopes)})
}
table.Render()
return
case "token create":
scps := *tokenCreateScopes
tkn := &proto.Token{
Scopes: scps,
}
ftkn, err := tc.Put(ctx, tkn)
if err != nil {
ln.FatalErr(ctx, err, ln.Action("put token to server"))
}
fmt.Printf("Your token is: %s\n", ftkn.Body)
fmt.Printf("It has permission for the following scopes: %v\n", ftkn.Scopes)
return
}
ln.Fatal(ctx, ln.Action("not implemented"), ln.F{"command": cmdline})
}

View File

@ -1,9 +1,9 @@
package main
import (
"context"
"crypto/tls"
"flag"
"os"
"git.xeserv.us/xena/route/lib/tun2"
"github.com/Xe/ln"
@ -34,9 +34,6 @@ func main() {
client, _ := tun2.NewClient(cfg)
err := client.Connect()
if err != nil {
ln.Error(err, ln.F{
"action": "client_running",
})
os.Exit(1)
ln.FatalErr(context.Background(), err, ln.Action("http agent is now running"))
}
}

View File

@ -1,14 +1,16 @@
package main
import (
"context"
"crypto/tls"
"flag"
"log"
"math/rand"
"net"
"net/http"
"time"
_ "git.xeserv.us/xena/route/internal"
"git.xeserv.us/xena/route/internal/middleware"
"git.xeserv.us/xena/route/internal/routecrypto"
"git.xeserv.us/xena/route/internal/server"
"github.com/Xe/ln"
@ -25,31 +27,34 @@ func main() {
flag.Parse()
flagenv.Parse()
rand.Seed(time.Now().Unix())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
certKey, _ := routecrypto.ParseKey(*sslCertKey)
scfg := server.Config{}
err := env.Parse(&scfg)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "env.Parse()"})
ln.FatalErr(ctx, err, ln.Action("parsing environment for config"))
}
scfg.CertKey = certKey
s, err := server.New(scfg)
if err != nil {
log.Fatal(err)
ln.FatalErr(ctx, err, ln.Action("create server instance"))
}
go setupTLS(s, scfg)
// listen on HTTP listener
l, err := net.Listen("tcp", scfg.WebAddr)
if err != nil {
log.Fatal(err)
ln.FatalErr(ctx, err, ln.Action("listening on HTTP port"), ln.F{"addr": scfg.WebAddr})
}
defer l.Close()
hs := &http.Server{
Handler: s,
Handler: middleware.Trace(s),
Addr: scfg.WebAddr,
}
@ -58,12 +63,14 @@ func main() {
func setupTLS(s *server.Server, scfg server.Config) {
hs := &http.Server{
Handler: s,
Handler: middleware.Trace(s),
Addr: scfg.SSLAddr,
TLSConfig: &tls.Config{
GetCertificate: s.GetCertificate,
},
}
hs.ListenAndServeTLS("", "")
for {
hs.ListenAndServeTLS("", "")
}
}

View File

@ -56,7 +56,7 @@ func (b *BoltDBStorage) GetRoute(ctx context.Context, host string) (Route, error
r := Route{}
err := b.db.One("Hostname", host, &r)
if err != nil {
ln.Error(err, ln.F{"err": err, "action": "route_get_route"})
ln.Error(ctx, err, ln.F{"err": err, "action": "route_get_route"})
switch err {
case storm.ErrNotFound:

View File

@ -1,4 +1,4 @@
package main
package internal
import (
"log"

11
internal/init.go Normal file
View File

@ -0,0 +1,11 @@
// Package internal contains autoloading packages and tools.
package internal
import (
"github.com/Xe/ln"
"github.com/Xe/ln/ex"
)
func init() {
ln.DefaultLogger.Filters = append(ln.DefaultLogger.Filters, ex.NewGoTraceLogger())
}

27
internal/manhole.go Normal file
View File

@ -0,0 +1,27 @@
package internal
import (
"log"
"net"
"net/http"
"net/rpc"
// Add HTTP pprof routes
_ "net/http/pprof"
// Add tracing routes
_ "golang.org/x/net/trace"
)
func init() {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
log.Printf("manhole: cannot bind to 127.0.0.1:0: %v", err)
return
}
log.Printf("manhole: Now listening on http://%s", l.Addr())
rpc.HandleHTTP()
go http.Serve(l, nil)
}

View File

@ -0,0 +1,41 @@
package middleware
import (
"context"
"net/http"
"os"
"path/filepath"
"time"
"github.com/Xe/ln"
"golang.org/x/net/trace"
)
// Trace adds go stdlib tracing to this http handler.
func Trace(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sp := trace.New(filepath.Base(os.Args[0]), "http://"+r.Host+r.RequestURI)
defer sp.Finish()
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
ctx = trace.NewContext(ctx, sp)
f := ln.F{
"method": r.Method,
"path": r.URL.Path,
"remote_addr": r.RemoteAddr,
"user_agent": r.UserAgent(),
}
next.ServeHTTP(w, r.WithContext(ctx))
ws, ok := w.(interface {
Status() int
})
if ok {
f["status"] = ws.Status()
}
ln.Log(ctx, f)
})
}

View File

@ -3,7 +3,9 @@ package server
import (
"git.xeserv.us/xena/route/lib/tun2"
proto "git.xeserv.us/xena/route/proto"
"github.com/Xe/ln"
"golang.org/x/net/context"
"golang.org/x/net/trace"
)
// Backend implements proto.BackendsServer for gRPC.
@ -13,6 +15,14 @@ type Backend struct {
// List returns a list of backends given filtering parameters.
func (b *Backend) List(ctx context.Context, sel *proto.BackendSelector) (*proto.BackendList, error) {
ctx, clitok, err := b.getAuth(ctx, "backend list", "backend:list")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "authentication for backend list"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
bl := map[string]tun2.Backend{}
switch {
@ -51,9 +61,19 @@ func (b *Backend) List(ctx context.Context, sel *proto.BackendSelector) (*proto.
// Kill removes a backend's connection by ID.
func (b *Backend) Kill(ctx context.Context, bid *proto.BackendID) (*proto.Nil, error) {
if err := b.ts.KillBackend(bid.Id); err != nil {
return nil, err
ctx, clitok, err := b.getAuth(ctx, "backend list", "backend:list")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "authentication for backend list"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
if err := b.ts.KillBackend(bid.Id); err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "killing backend", "backend_id": bid.Id})
}
ln.Log(ctx, clitok, ln.Action("backend killed"), ln.F{"backend_id": bid.Id})
return &proto.Nil{}, nil
}

View File

@ -6,6 +6,7 @@ import (
"git.xeserv.us/xena/route/internal/database"
"github.com/Xe/ln"
"golang.org/x/net/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@ -16,23 +17,23 @@ var (
ErrNotAuthorized = errors.New("server: not authorized")
)
func (s *Server) getAuth(ctx context.Context, scope string) (database.Token, error) {
func (s *Server) getAuth(ctx context.Context, operation, scope string) (context.Context, database.Token, error) {
var err error
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
}
jwtToken, ok := md["authorization"]
if !ok {
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
}
val := jwtToken[0]
t, err := s.db.GetToken(ctx, val)
if err != nil {
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "valid token required.")
}
ok = false
@ -42,14 +43,24 @@ func (s *Server) getAuth(ctx context.Context, scope string) (database.Token, err
}
}
if !ok {
return database.Token{}, grpc.Errorf(codes.Unauthenticated, "invalid scope.")
return nil, database.Token{}, grpc.Errorf(codes.Unauthenticated, "invalid scope.")
}
return t, nil
tr := trace.New("routed-grpc", operation)
ctx = trace.NewContext(ctx, tr)
return ctx, t, nil
}
func handleError(ctx context.Context, clitok database.Token, err error, f ln.F) error {
ln.Error(err, f, clitok.F())
tr, ok := trace.FromContext(ctx)
if !ok {
goto skip
}
tr.SetError()
skip:
ln.Error(ctx, err, f, clitok)
return err
}

View File

@ -5,6 +5,7 @@ import (
proto "git.xeserv.us/xena/route/proto"
"github.com/Xe/ln"
"golang.org/x/net/context"
"golang.org/x/net/trace"
)
// Route implements rout.RoutesServer for gRPC
@ -19,16 +20,17 @@ var (
// Get fetches a route from the database.
func (r *Route) Get(ctx context.Context, req *proto.GetRouteRequest) (*proto.Route, error) {
clitok, err := r.getAuth(ctx, "route:get")
ctx, clitok, err := r.getAuth(ctx, "get single route", "route:get")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Get_getAuth"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
val, err := r.db.GetRoute(ctx, req.Host)
if err != nil {
ln.Error(err, ln.F{"action": "Route.Get"})
return nil, err
return nil, handleError(ctx, clitok, err, ln.F{"action": "get single route from database", "host": req.Host})
}
if val.Creator != clitok.Owner {
@ -40,16 +42,17 @@ func (r *Route) Get(ctx context.Context, req *proto.GetRouteRequest) (*proto.Rou
// GetAll fetches all of the routes that you own.
func (r *Route) GetAll(ctx context.Context, req *proto.Nil) (*proto.GetAllRoutesResponse, error) {
clitok, err := r.getAuth(ctx, "route:getall")
ctx, clitok, err := r.getAuth(ctx, "get all routes for user", "route:getall")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.GetAll_getAuth"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
routes, err := r.db.GetAllRoutes(ctx, clitok.Owner)
if err != nil {
ln.Error(err, ln.F{"action": "Route.GetAll"})
return nil, err
return nil, handleError(ctx, clitok, err, ln.F{"action": "get all routes for user from database"})
}
result := []*proto.Route{}
@ -65,23 +68,24 @@ func (r *Route) GetAll(ctx context.Context, req *proto.Nil) (*proto.GetAllRoutes
}
func (r *Route) Put(ctx context.Context, rt *proto.Route) (*proto.IDResponse, error) {
clitok, err := r.getAuth(ctx, "route:put")
ctx, clitok, err := r.getAuth(ctx, "put new route", "route:put")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Put_getAuth"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
if rt.Host == "" {
rt.Host = elfs.MakeName() + r.cfg.DomainSuffix
}
drt, err := r.db.PutRoute(ctx, rt.Host, clitok.Owner)
if err != nil {
ln.Error(err, ln.F{"action": "Route.Put"})
return nil, err
return nil, handleError(ctx, clitok, err, ln.F{"action": "put route to database"})
}
ln.Log(drt.F(), ln.F{"action": "Route.Put_success"})
ln.Log(ctx, drt, ln.Action("created new route"))
return &proto.IDResponse{
Id: drt.ID,
@ -89,30 +93,32 @@ func (r *Route) Put(ctx context.Context, rt *proto.Route) (*proto.IDResponse, er
}
func (r *Route) Delete(ctx context.Context, rt *proto.Route) (*proto.IDResponse, error) {
clitok, err := r.getAuth(ctx, "route:delete")
ctx, clitok, err := r.getAuth(ctx, "delete single route", "route:delete")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Route.Delete_getAuth"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
drt, err := r.db.GetRoute(ctx, rt.Host)
if err != nil {
ln.Error(err, ln.F{"action": "Route.Delete_getRoute_verify"})
return nil, err
return nil, handleError(ctx, clitok, err, ln.F{"action": "fetch route from database", "host": rt.Host})
}
if drt.Creator != clitok.Owner {
return nil, handleError(ctx, clitok, ErrNotAuthorized, ln.F{"action": "Route.Delete_not_authorized"})
return nil, handleError(ctx, clitok, ErrNotAuthorized, ln.F{"action": "user not authorized to delete this route", "host": rt.Host})
}
err = r.db.DeleteRoute(ctx, rt.Id)
f := drt.F()
f["action"] = "Route.Delete_db.DeleteRoute"
f["action"] = "delete route from database"
if err != nil {
handleError(ctx, clitok, ErrNotAuthorized, f)
}
ln.Log(f, drt.F())
f["action"] = "deleted route from database"
ln.Log(ctx, f, drt)
return &proto.IDResponse{Id: rt.Id}, nil
}

View File

@ -5,6 +5,7 @@ import (
"github.com/Xe/ln"
"github.com/Xe/uuid"
"golang.org/x/net/context"
"golang.org/x/net/trace"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@ -20,11 +21,14 @@ var (
)
func (t *Token) Get(ctx context.Context, req *proto.GetTokenRequest) (*proto.Token, error) {
clitok, err := t.getAuth(ctx, "token:get")
ctx, clitok, err := t.getAuth(ctx, "get single token", "token:get")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Get_getAuth"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
if req.Id == "" {
return nil, status.Errorf(codes.InvalidArgument, "must specify ID")
}
@ -42,11 +46,14 @@ func (t *Token) Get(ctx context.Context, req *proto.GetTokenRequest) (*proto.Tok
}
func (t *Token) GetAll(ctx context.Context, req *proto.Nil) (*proto.TokenSet, error) {
clitok, err := t.getAuth(ctx, "token:getall")
ctx, clitok, err := t.getAuth(ctx, "get all tokens", "token:getall")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_getAuth"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
toks, err := t.db.GetTokensForOwner(ctx, clitok.Owner)
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_db.GetTokensForOwner"})
@ -64,43 +71,58 @@ func (t *Token) GetAll(ctx context.Context, req *proto.Nil) (*proto.TokenSet, er
}
func (t *Token) Put(ctx context.Context, tok *proto.Token) (*proto.Token, error) {
clitok, err := t.getAuth(ctx, "token:put")
ctx, clitok, err := t.getAuth(ctx, "put new token", "token:put")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Put_getAuth"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
dbt, err := t.db.PutToken(ctx, uuid.New(), clitok.Owner, tok.Scopes)
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Put_db.PutToken"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "put token into database", "scopes": tok.Scopes})
}
ln.Log(ctx, dbt, ln.Action("new token created"))
return dbt.AsProto(), nil
}
func (t *Token) Delete(ctx context.Context, tok *proto.Token) (*proto.Nil, error) {
clitok, err := t.getAuth(ctx, "token:delete")
ctx, clitok, err := t.getAuth(ctx, "delete single token", "token:delete")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Delete_getAuth"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
err = t.db.DeleteToken(ctx, tok.Id)
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Delete_db.DeleteToken"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "delete token from database", "token_id": tok.Id})
}
ln.Log(ctx, clitok, ln.Action("token deleted"), ln.F{"token_id": tok.Id})
return &proto.Nil{}, nil
}
func (t *Token) Deactivate(ctx context.Context, tok *proto.Token) (*proto.Nil, error) {
clitok, err := t.getAuth(ctx, "token:deactivate")
ctx, clitok, err := t.getAuth(ctx, "deactivate single token", "token:deactivate")
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Deactivate_getAuth"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "not authorized"})
}
tr, _ := trace.FromContext(ctx)
defer tr.Finish()
err = t.db.DeactivateToken(ctx, tok.Id)
if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.Deactivate_db.DeactivateToken"})
return nil, handleError(ctx, clitok, err, ln.F{"action": "deactivate token in database", "token_id": tok.Id})
}
ln.Log(ctx, clitok, ln.Action("deactivated token"), ln.F{"token_id": tok.Id})
return &proto.Nil{}, nil
}

View File

@ -50,14 +50,18 @@ func (c *Connection) F() ln.F {
// Ping ends a "ping" to the client. If the client doesn't respond or the connection
// dies, then the connection needs to be cleaned up.
func (c *Connection) Ping() error {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
req, err := http.NewRequest("GET", "http://backend/health", nil)
if err != nil {
panic(err)
}
req = req.WithContext(ctx)
_, err = c.RoundTrip(req)
if err != nil {
ln.Error(err, c.F(), ln.F{"action": "ping_roundtrip"})
ln.Error(ctx, err, c, ln.Action("pinging the backend"))
return err
}
@ -67,20 +71,20 @@ func (c *Connection) Ping() error {
}
// OpenStream creates a new stream (connection) to the backend server.
func (c *Connection) OpenStream() (net.Conn, error) {
func (c *Connection) OpenStream(ctx context.Context) (net.Conn, error) {
if !c.usable {
return nil, ErrNoSuchBackend
}
err := c.conn.SetDeadline(time.Now().Add(time.Second))
if err != nil {
ln.Error(err, c.F())
ln.Error(ctx, err, c)
return nil, err
}
stream, err := c.session.OpenStream()
if err != nil {
ln.Error(err, c.F())
ln.Error(ctx, err, c)
return nil, err
}
@ -117,7 +121,7 @@ var (
// RoundTrip forwards a HTTP request to the remote backend and then returns the
// response, if any.
func (c *Connection) RoundTrip(req *http.Request) (*http.Response, error) {
stream, err := c.OpenStream()
stream, err := c.OpenStream(req.Context())
if err != nil {
return nil, errors.Wrap(err, ErrCantOpenSessionStream.Error())
}

View File

@ -146,7 +146,10 @@ func (s *Server) GetAllBackends() []Backend {
// ListenAndServe starts the backend TCP/KCP listeners and relays backend
// traffic to and from them.
func (s *Server) ListenAndServe() error {
ln.Log(ln.F{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ln.Log(ctx, ln.F{
"action": "listen_and_serve_called",
})
@ -157,7 +160,7 @@ func (s *Server) ListenAndServe() error {
panic(err)
}
ln.Log(ln.F{
ln.Log(ctx, ln.F{
"action": "tcp+tls_listening",
"addr": l.Addr(),
})
@ -165,11 +168,11 @@ func (s *Server) ListenAndServe() error {
for {
conn, err := l.Accept()
if err != nil {
ln.Error(err, ln.F{"kind": "tcp", "addr": l.Addr().String()})
ln.Error(ctx, err, ln.F{"kind": "tcp", "addr": l.Addr().String()})
continue
}
ln.Log(ln.F{
ln.Log(ctx, ln.F{
"action": "new_client",
"kcp": false,
"addr": conn.RemoteAddr(),
@ -187,7 +190,7 @@ func (s *Server) ListenAndServe() error {
panic(err)
}
ln.Log(ln.F{
ln.Log(ctx, ln.F{
"action": "kcp+tls_listening",
"addr": l.Addr(),
})
@ -195,10 +198,10 @@ func (s *Server) ListenAndServe() error {
for {
conn, err := l.Accept()
if err != nil {
ln.Error(err, ln.F{"kind": "kcp", "addr": l.Addr().String()})
ln.Error(ctx, err, ln.F{"kind": "kcp", "addr": l.Addr().String()})
}
ln.Log(ln.F{
ln.Log(ctx, ln.F{
"action": "new_client",
"kcp": true,
"addr": conn.RemoteAddr(),
@ -223,7 +226,7 @@ func (s *Server) ListenAndServe() error {
failureChance := c.detector.Phi(now)
if failureChance > 0.8 {
ln.Log(c.F(), ln.F{
ln.Log(ctx, c.F(), ln.F{
"action": "phi_failure_detection",
"value": failureChance,
})
@ -247,7 +250,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
session, err := smux.Server(c, s.cfg.SmuxConf)
if err != nil {
ln.Error(err, ln.F{
ln.Error(ctx, err, ln.F{
"action": "session_failure",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -261,7 +264,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
controlStream, err := session.OpenStream()
if err != nil {
ln.Error(err, ln.F{
ln.Error(ctx, err, ln.F{
"action": "control_stream_failure",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -275,7 +278,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
auth := &Auth{}
err = csd.Decode(auth)
if err != nil {
ln.Error(err, ln.F{
ln.Error(ctx, err, ln.F{
"action": "control_stream_auth_decoding_failure",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -286,7 +289,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
routeUser, err := s.cfg.Storage.HasRoute(auth.Domain)
if err != nil {
ln.Error(err, ln.F{
ln.Error(ctx, err, ln.F{
"action": "nosuch_domain",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -297,7 +300,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
tokenUser, scopes, err := s.cfg.Storage.HasToken(auth.Token)
if err != nil {
ln.Error(err, ln.F{
ln.Error(ctx, err, ln.F{
"action": "nosuch_token",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -315,7 +318,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
}
if !ok {
ln.Error(ErrAuthMismatch, ln.F{
ln.Error(ctx, ErrAuthMismatch, ln.F{
"action": "token_not_authorized",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -323,7 +326,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
}
if routeUser != tokenUser {
ln.Error(ErrAuthMismatch, ln.F{
ln.Error(ctx, ErrAuthMismatch, ln.F{
"action": "auth_mismatch",
"local": c.LocalAddr().String(),
"remote": c.RemoteAddr().String(),
@ -346,11 +349,11 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
defer func() {
if r := recover(); r != nil {
ln.Log(connection, ln.F{"action": "connection handler panic", "err": r})
ln.Log(ctx, connection, ln.F{"action": "connection handler panic", "err": r})
}
}()
ln.Log(ln.F{
ln.Log(ctx, ln.F{
"action": "backend_connected",
}, connection.F())
@ -386,7 +389,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
connection.cancel()
}
case <-ctx.Done():
s.RemoveConn(connection)
s.RemoveConn(ctx, connection)
connection.Close()
return
@ -395,7 +398,7 @@ func (s *Server) HandleConn(c net.Conn, isKCP bool) {
}
// RemoveConn removes a connection.
func (s *Server) RemoveConn(connection *Connection) {
func (s *Server) RemoveConn(ctx context.Context, connection *Connection) {
s.connlock.Lock()
delete(s.conns, connection.conn)
s.connlock.Unlock()
@ -408,7 +411,7 @@ func (s *Server) RemoveConn(connection *Connection) {
if ok {
conns, ok = val.([]*Connection)
if !ok {
ln.Error(ErrCantRemoveWhatDoesntExist, connection.F(), ln.F{
ln.Error(ctx, ErrCantRemoveWhatDoesntExist, connection.F(), ln.F{
"action": "looking_up_for_disconnect_removal",
})
return
@ -428,7 +431,7 @@ func (s *Server) RemoveConn(connection *Connection) {
s.domains.Remove(auth.Domain)
}
ln.Log(connection.F(), ln.F{
ln.Log(ctx, connection.F(), ln.F{
"action": "client_disconnecting",
})
}
@ -469,12 +472,13 @@ func gen502Page(req *http.Request) *http.Response {
// RoundTrip sends a HTTP request to a backend and then returns its response.
func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
var conns []*Connection
ctx := req.Context()
val, ok := s.domains.Get(req.Host)
if ok {
conns, ok = val.([]*Connection)
if !ok {
ln.Error(ErrNoSuchBackend, ln.F{
ln.Error(ctx, ErrNoSuchBackend, ln.F{
"action": "no_backend_connected",
"remote": req.RemoteAddr,
"host": req.Host,
@ -493,7 +497,7 @@ func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
}
if len(goodConns) == 0 {
ln.Error(ErrNoSuchBackend, ln.F{
ln.Error(ctx, ErrNoSuchBackend, ln.F{
"action": "no_backend_connected",
"remote": req.RemoteAddr,
"host": req.Host,
@ -507,7 +511,7 @@ func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := c.RoundTrip(req)
if err != nil {
ln.Error(err, c.F(), ln.F{
ln.Error(ctx, err, c, ln.F{
"action": "connection_roundtrip",
})
@ -515,7 +519,7 @@ func (s *Server) RoundTrip(req *http.Request) (*http.Response, error) {
return nil, err
}
ln.Log(c.F(), ln.F{
ln.Log(ctx, c, ln.F{
"action": "http_traffic",
"remote_addr": req.RemoteAddr,
"host": req.Host,

View File

@ -323,3 +323,10 @@ b6e1ae21643682ce023deb8d152024597b0e9bb4 golang.org/x/sys/unix
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/status
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/tap
8443e311d3925f5e20494496790670942ed48504 google.golang.org/grpc/transport
466e05b2ef3e48ce08a367b6aaac09ee29a124e5 github.com/Xe/ln
2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb github.com/pkg/errors
466e05b2ef3e48ce08a367b6aaac09ee29a124e5 github.com/Xe/ln
466e05b2ef3e48ce08a367b6aaac09ee29a124e5 github.com/Xe/ln/ex
2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb github.com/pkg/errors
0a9397675ba34b2845f758fe3cd68828369c6517 golang.org/x/net/internal/timeseries
0a9397675ba34b2845f758fe3cd68828369c6517 golang.org/x/net/trace

11
vendor/github.com/Xe/ln/action.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
package ln
// Action is a convenience helper for logging the "action" being performed as
// part of a log line.
//
// It is a convenience wrapper for the following:
//
// ln.Log(ctx, fer, f, ln.Action("writing frozberry sales reports to database"))
func Action(act string) Fer {
return F{"action": act}
}

38
vendor/github.com/Xe/ln/context.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
package ln
import (
"context"
)
type ctxKey int
const (
fKey = iota
)
// WithF stores or appends a given F instance into a context.
func WithF(ctx context.Context, f F) context.Context {
pf, ok := FFromContext(ctx)
if !ok {
return context.WithValue(ctx, fKey, f)
}
pf.Extend(f)
return context.WithValue(ctx, fKey, pf)
}
// FFromContext fetches the `F` out of the context if it exists.
func FFromContext(ctx context.Context) (F, bool) {
fvp := ctx.Value(fKey)
if fvp == nil {
return nil, false
}
f, ok := fvp.(F)
if !ok {
return nil, false
}
return f, true
}

7
vendor/github.com/Xe/ln/ex/doc.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
/*
Package ex is a set of extensions and middleware for ln.
This package will (inevitably) have a lot of third-party dependencies and
as such might be broken apart into other packages in the future.
*/
package ex

68
vendor/github.com/Xe/ln/ex/gotrace.go generated vendored Normal file
View File

@ -0,0 +1,68 @@
package ex
import (
"context"
"log"
"github.com/Xe/ln"
"golang.org/x/net/trace"
)
type goEventLogger struct {
ev trace.EventLog
}
// NewGoEventLogger will log ln information to a given trace.EventLog instance.
func NewGoEventLogger(ev trace.EventLog) ln.Filter {
return &goEventLogger{ev: ev}
}
func (gel *goEventLogger) Apply(ctx context.Context, e ln.Event) bool {
data, err := ln.DefaultFormatter.Format(ctx, e)
if err != nil {
log.Printf("wtf: error in log formatting: %v", err)
return false
}
if everr := e.Data["err"]; everr != nil {
gel.ev.Errorf("%s", string(data))
return true
}
gel.ev.Printf("%s", string(data))
return true
}
func (gel *goEventLogger) Close() { gel.ev.Finish() }
func (gel *goEventLogger) Run() {}
type sst string
func (s sst) String() string { return string(s) }
func goTraceLogger(ctx context.Context, e ln.Event) bool {
sp, ok := trace.FromContext(ctx)
if !ok {
return true // no trace in context
}
data, err := ln.DefaultFormatter.Format(ctx, e)
if err != nil {
log.Printf("wtf: error in log formatting: %v", err)
return false
}
if everr := e.Data["err"]; everr != nil {
sp.SetError()
}
sp.LazyLog(sst(string(data)), false)
return true
}
// NewGoTraceLogger will log ln information to a golang.org/x/net/trace.Trace
// if it is present in the context of ln calls.
func NewGoTraceLogger() ln.Filter {
return ln.FilterFunc(goTraceLogger)
}

36
vendor/github.com/Xe/ln/ex/http.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
package ex
import (
"net"
"net/http"
"time"
"github.com/Xe/ln"
)
func HTTPLog(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host, _, _ := net.SplitHostPort(r.RemoteAddr)
f := ln.F{
"remote_ip": host,
"x_forwarded_for": r.Header.Get("X-Forwarded-For"),
"path": r.URL.Path,
}
ctx := ln.WithF(r.Context(), f)
st := time.Now()
next.ServeHTTP(w, r.WithContext(ctx))
af := time.Now()
f["request_duration"] = af.Sub(st)
ws, ok := w.(interface {
Status() int
})
if ok {
f["status"] = ws.Status()
}
ln.Log(r.Context(), f)
})
}

25
vendor/github.com/Xe/ln/ex/l2met.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
package ex
import (
"time"
"github.com/Xe/ln"
)
// This file deals with formatting of [l2met] style metrics.
// [l2met]: https://r.32k.io/l2met-introduction
// Counter formats a value as a metrics counter.
func Counter(name string, value int) ln.Fer {
return ln.F{"count#" + name: value}
}
// Gauge formats a value as a metrics gauge.
func Gauge(name string, value int) ln.Fer {
return ln.F{"gauge#" + name: value}
}
// Measure formats a value as a metrics measure.
func Measure(name string, ts time.Time) ln.Fer {
return ln.F{"measure#" + name: time.Since(ts)}
}

15
vendor/github.com/Xe/ln/filter.go generated vendored
View File

@ -1,23 +1,24 @@
package ln
import (
"context"
"io"
"sync"
)
// Filter interface for defining chain filters
type Filter interface {
Apply(Event) bool
Apply(ctx context.Context, e Event) bool
Run()
Close()
}
// FilterFunc allows simple functions to implement the Filter interface
type FilterFunc func(e Event) bool
type FilterFunc func(ctx context.Context, e Event) bool
// Apply implements the Filter interface
func (ff FilterFunc) Apply(e Event) bool {
return ff(e)
func (ff FilterFunc) Apply(ctx context.Context, e Event) bool {
return ff(ctx, e)
}
// Run implements the Filter interface
@ -45,8 +46,8 @@ func NewWriterFilter(out io.Writer, format Formatter) *WriterFilter {
}
// Apply implements the Filter interface
func (w *WriterFilter) Apply(e Event) bool {
output, err := w.Formatter.Format(e)
func (w *WriterFilter) Apply(ctx context.Context, e Event) bool {
output, err := w.Formatter.Format(ctx, e)
if err == nil {
w.Lock()
w.Out.Write(output)
@ -63,4 +64,4 @@ func (w *WriterFilter) Run() {}
func (w *WriterFilter) Close() {}
// NilFilter is safe to return as a Filter, but does nothing
var NilFilter = FilterFunc(func(e Event) bool { return true })
var NilFilter = FilterFunc(func(_ context.Context, e Event) bool { return true })

View File

@ -2,6 +2,7 @@ package ln
import (
"bytes"
"context"
"fmt"
"time"
)
@ -13,7 +14,7 @@ var (
// Formatter defines the formatting of events
type Formatter interface {
Format(Event) ([]byte, error)
Format(ctx context.Context, e Event) ([]byte, error)
}
// DefaultFormatter is the default way in which to format events
@ -36,7 +37,7 @@ func NewTextFormatter() Formatter {
}
// Format implements the Formatter interface
func (t *TextFormatter) Format(e Event) ([]byte, error) {
func (t *TextFormatter) Format(_ context.Context, e Event) ([]byte, error) {
var writer bytes.Buffer
writer.WriteString("time=\"")

42
vendor/github.com/Xe/ln/logger.go generated vendored
View File

@ -1,6 +1,7 @@
package ln
import (
"context"
"os"
"time"
@ -61,7 +62,7 @@ type Event struct {
}
// Log is the generic logging method.
func (l *Logger) Log(xs ...Fer) {
func (l *Logger) Log(ctx context.Context, xs ...Fer) {
event := Event{Time: time.Now()}
addF := func(bf F) {
@ -78,6 +79,11 @@ func (l *Logger) Log(xs ...Fer) {
addF(f.F())
}
ctxf, ok := FFromContext(ctx)
if ok {
addF(ctxf)
}
if os.Getenv("LN_DEBUG_ALL_EVENTS") == "1" {
frame := callersFrame()
if event.Data == nil {
@ -88,19 +94,19 @@ func (l *Logger) Log(xs ...Fer) {
event.Data["_filename"] = frame.filename
}
l.filter(event)
l.filter(ctx, event)
}
func (l *Logger) filter(e Event) {
func (l *Logger) filter(ctx context.Context, e Event) {
for _, f := range l.Filters {
if !f.Apply(e) {
if !f.Apply(ctx, e) {
return
}
}
}
// Error logs an error and information about the context of said error.
func (l *Logger) Error(err error, xs ...Fer) {
func (l *Logger) Error(ctx context.Context, err error, xs ...Fer) {
data := F{}
frame := callersFrame()
@ -116,20 +122,20 @@ func (l *Logger) Error(err error, xs ...Fer) {
xs = append(xs, data)
l.Log(xs...)
l.Log(ctx, xs...)
}
// Fatal logs this set of values, then exits with status code 1.
func (l *Logger) Fatal(xs ...Fer) {
func (l *Logger) Fatal(ctx context.Context, xs ...Fer) {
xs = append(xs, F{"fatal": true})
l.Log(xs...)
l.Log(ctx, xs...)
os.Exit(1)
}
// FatalErr combines Fatal and Error.
func (l *Logger) FatalErr(err error, xs ...Fer) {
func (l *Logger) FatalErr(ctx context.Context, err error, xs ...Fer) {
xs = append(xs, F{"fatal": true})
data := F{}
@ -146,7 +152,7 @@ func (l *Logger) FatalErr(err error, xs ...Fer) {
}
xs = append(xs, data)
l.Log(xs...)
l.Log(ctx, xs...)
os.Exit(1)
}
@ -154,21 +160,21 @@ func (l *Logger) FatalErr(err error, xs ...Fer) {
// Default Implementation
// Log is the generic logging method.
func Log(xs ...Fer) {
DefaultLogger.Log(xs...)
func Log(ctx context.Context, xs ...Fer) {
DefaultLogger.Log(ctx, xs...)
}
// Error logs an error and information about the context of said error.
func Error(err error, xs ...Fer) {
DefaultLogger.Error(err, xs...)
func Error(ctx context.Context, err error, xs ...Fer) {
DefaultLogger.Error(ctx, err, xs...)
}
// Fatal logs this set of values, then exits with status code 1.
func Fatal(xs ...Fer) {
DefaultLogger.Fatal(xs...)
func Fatal(ctx context.Context, xs ...Fer) {
DefaultLogger.Fatal(ctx, xs...)
}
// FatalErr combines Fatal and Error.
func FatalErr(err error, xs ...Fer) {
DefaultLogger.FatalErr(err, xs...)
func FatalErr(ctx context.Context, err error, xs ...Fer) {
DefaultLogger.FatalErr(ctx, err, xs...)
}