internal/server: add grpc tracing

This commit is contained in:
Cadey Ratio 2017-10-01 08:06:27 -07:00
parent e1ce5dfd53
commit dc40bfa5ba
No known key found for this signature in database
GPG Key ID: D607EE27C2E7F89A
4 changed files with 98 additions and 39 deletions

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@ import (
"github.com/Xe/ln" "github.com/Xe/ln"
"github.com/Xe/uuid" "github.com/Xe/uuid"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/net/trace"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
) )
@ -20,11 +21,14 @@ var (
) )
func (t *Token) Get(ctx context.Context, req *proto.GetTokenRequest) (*proto.Token, error) { 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 { 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 == "" { if req.Id == "" {
return nil, status.Errorf(codes.InvalidArgument, "must specify 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) { 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 { if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_getAuth"}) 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) toks, err := t.db.GetTokensForOwner(ctx, clitok.Owner)
if err != nil { if err != nil {
return nil, handleError(ctx, clitok, err, ln.F{"action": "Token.GetAll_db.GetTokensForOwner"}) 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) { 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 { 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) dbt, err := t.db.PutToken(ctx, uuid.New(), clitok.Owner, tok.Scopes)
if err != nil { 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 return dbt.AsProto(), nil
} }
func (t *Token) Delete(ctx context.Context, tok *proto.Token) (*proto.Nil, error) { 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 { 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) err = t.db.DeleteToken(ctx, tok.Id)
if err != nil { 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 return &proto.Nil{}, nil
} }
func (t *Token) Deactivate(ctx context.Context, tok *proto.Token) (*proto.Nil, error) { 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 { 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) err = t.db.DeactivateToken(ctx, tok.Id)
if err != nil { 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 return &proto.Nil{}, nil
} }