...

Package server

import "golang.conradwood.net/go-easyops/server"
Overview
Index

Overview ▾

implements the server-side of gRPC.

As part of the https://www.yacloud.eu cloud the server registers itself upon startup and thus becomes accessible for other servers and clients.

Registration

Typically, servers register at the yacloud registry (registry.yacloud.eu). It is also possible (albeit discouraged) to run a private cloud with the yacloud software.

The server needs at least a registry and authentication service(s).

Servers can also be run in standalone mode (see -ge_standalone option). If so, they need no external services, but are limited to local clients and no load-balancing, failover or authentication.

Multiple instances of the same server may register at the registry. Which server is chosen for any one rpc is handled in the client (see client package).

Types

The Server supports 3 types of services:

  • gRPC (default), see NewServerDef()

  • TCP, see NewTCPServerDef(name)

  • HTML, deprecated.

  • Status, information about the status of this instance. Automatically added.

gRPC server

this is the default and most commonly used service type. The server registers with the registry and claims to support the gRPC protocol. This implementation also automatically adds 'Status' to any gRPC servers. gRPC calls are authenticated, that is, all calls require either a user or a service in the context. Calls with neither of the two will be rejected. Whilst this behaviour can be changed, it should only be required for low-level services. For example, the registry must accept rpc calls without authentication, because the first calls to the registry will be a lookup for the auth-service, which is required to create user objects in contexts. (chicken and egg...)

a server is typically started like this:

sd := server.NewServerDef()
sd.SetPort(4100)
sd.SetRegister(server.Register(
func(g *grpc.Server) error {
  pb.RegisterEchoServiceServer(g, &echoServer{})
  return nil
},
))
err := server.ServerStartup(sd)

the "echoServer" is required to implement the service definition as defined by the .proto file.

TCP server

this is a server that exposes a proprietary TCP connection on a port. The server instance registers the port at the registry, so that edge proxies (like h2gproxy) may proxy tcp connections to instances.

Status server

this exposes an http api. Help can be found at [instance:port]/internal/help, for example https://10.1.1.1:4100/internal/help. Status is a bit of a misnomer. With the status api, one can:

  • shutdown the service
  • query the instance health
  • query the build information, including instance version
  • retrieve metrics (compatible with prometheus)
  • clear cache(s) of the instances
  • change commandline flags on-the-fly
  • view current outbound grpc Connections of this instance
  • view registered (as supposed to current) grpc connetions
  • download go debug information of this instance

Constants

const (
    COOKIE_NAME = "Auth-Token"
)

Variables

var (
    BuiltinCert    []byte          // set on server startup
    BuiltinKey     []byte          // set on server startup
    BuiltinTLSCert tls.Certificate // set on server startup

)

func ActiveRPCs

func ActiveRPCs() int

func AddErrorDetail

func AddErrorDetail(st *status.Status, ct *ge.GRPCError) *status.Status

this will result status detail with grpcerrorlist, with a single GRPCErrorList.

func AddRegistry

func AddRegistry(sd *serverDef) (string, error)

func AddStatusDetail

func AddStatusDetail(st *status.Status, ct *fw.CallTrace) *status.Status

func Authenticate

func Authenticate(ictx context.Context, cs *rpc.CallState) error

authenticate a user (and authorise access to this method/service)

func GetHealth

func GetHealth() common.Health

func GetUsageInfo

func GetUsageInfo() *usage_info_tracker

func IsStopping

func IsStopping() bool

func MethodNameFromStreamInfo

func MethodNameFromStreamInfo(info *grpc.StreamServerInfo) string

func MethodNameFromUnaryInfo

func MethodNameFromUnaryInfo(info *grpc.UnaryServerInfo) string

func NewHTMLServerDef

func NewHTMLServerDef(name string) *serverDef

func NewTCPServerDef

func NewTCPServerDef(name string) *serverDef

func ServerStartup

func ServerStartup(sd ServerDef) error

this is our typical gRPC server startup it sets ourselves up with our own certificates which is set for THIS SERVER, so installed/maintained together with the server (rather than as part of this software) it also configures the rpc server to expect a token to identify the user in the rpc metadata call

func ServiceNameFromStreamInfo

func ServiceNameFromStreamInfo(info *grpc.StreamServerInfo) string

func ServiceNameFromUnaryInfo

func ServiceNameFromUnaryInfo(info *grpc.UnaryServerInfo) string

func SetHealth

func SetHealth(h common.Health) error

Set the health of this service. This is useful for services which have periods where they are unavailable. Typically this is directly after starting, but sometimes also a period where they gather data.

For a service with a delayed startup, the pattern is as follows:

	func main() {
	 server.SetHealth(common.Health_STARTING)
         go do_initialisation()
	}
        func do_initialisation() {
            doing_slow_things() // ...
            server.SetHealth(common.Health_READY)
        }

func SetQuietMode

func SetQuietMode()

func StartFakeService

func StartFakeService(name string)

************************************************** * convenience function to register stuff with the registry * useful to register long-running clients, for example * this allows for metrics to be exposed and scraped automatically * uses a default RPC **************************************************

func UnregisterPortRegistry

func UnregisterPortRegistry(port []int) error

mostly for autodeployer

type Register

type Register func(server *grpc.Server) error

type Server

server interface

type Server interface {
    AddTag(key, value string)
}

type ServerDef

type ServerDef interface {

    //if something needs to be done to errors before they propagate up the stack, then this hook can be used to do so
    SetErrorHandler(e func(ctx context.Context, fn string, err error))
    /*
     set to true if this server does NOT require authentication (default: it does need authentication).
     This should normally not be necessary. Normally, a service needs to be called with EITHER a service account OR a user account OR both. There are very special circumstances where this is not possible, for example, the registry and the auth service cannot be called with a service or user account, because in order to get one, the service needs to lookup and call the auth service. Thus registry and auth both expose their RPCs as "NoAuth". In normal circumstances this is never necessary.
    */
    SetNoAuth()
    // the tcp port to listen on
    SetPort(port int)
    // register the implementation of the gRPC service
    SetRegister(r Register)
    DontRegister() // if this service should not register with the registry initially
    // assume the service is directly accessible on a public ip. this disables functionalitity normally filtered out by proxies, such as /internal/ helpers and reflection. Normally not needed. Typically h2gproxy proxies requests.
    SetPublic()
    /*
       set a callback that is called AFTER grpc server started successfully
    */
    SetOnStartupCallback(f func())
    AddTag(key, value string) // add a routing tag to a serverdef

}

func NewServerDef

func NewServerDef() ServerDef

type ServerMetrics

deprecated - to be moved to global vars

type ServerMetrics struct {
    // contains filtered or unexported fields
}

func NewServerMetrics

func NewServerMetrics() *ServerMetrics

deprecated - to be moved to global vars

type UserCache

type UserCache struct {
    UserID string
    // contains filtered or unexported fields
}