rest

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 8, 2022 License: Apache-2.0 Imports: 25 Imported by: 2

Documentation

Index

Examples

Constants

View Source
const (
	// EvtSourceStatus specifies source for service Status
	EvtSourceStatus = "status"
	// EvtServiceStarted specifies Service Started event
	EvtServiceStarted = "service started"
	// EvtServiceStopped specifies Service Stopped event
	EvtServiceStopped = "service stopped"
)
View Source
const MaxRequestSize = 64 * 1024 * 1024

MaxRequestSize specifies max size of regular HTTP Post requests in bytes, 64 Mb

Variables

This section is empty.

Functions

func GetHostName

func GetHostName(bindAddr string) string

GetHostName returns Hostname from HTTP bind address, or OS Hostname, if it's not specified in the config

func GetPort

func GetPort(bindAddr string) string

GetPort returns the port from HTTP bind address, or standard HTTPS 443 port, if it's not specified in the config

func GetServerBaseURL

func GetServerBaseURL(s Server) *url.URL

GetServerBaseURL returns server base URL

func GetServerURL

func GetServerURL(s Server, r *http.Request, relativeEndpoint string) *url.URL

GetServerURL returns complete server URL for given relative end-point

Types

type Auditor

type Auditor interface {
	// Call at shutdown to cleanly close the audit destination
	io.Closer

	// Call Event to record a new Auditable event
	// Audit event
	// source indicates the area that the event was triggered by
	// eventType indicates the specific event that occured
	// identity specifies the identity of the user that triggered this event, typically this is <role>/<cn>
	// contextID specifies the request ContextID that the event was triggered in [this can be used for cross service correlation of logs]
	// raftIndex indicates the index# of the raft log in RAFT that the event occured in [if applicable]
	// message contains any additional information about this event that is eventType specific
	Audit(source string,
		eventType string,
		identity string,
		contextID string,
		raftIndex uint64,
		message string)
}

Auditor defines an interface that can receive information about audit events

type CORSOptions

type CORSOptions struct {
	// AllowedOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// An origin may contain a wildcard (*) to replace 0 or more characters
	// (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty.
	// Only one wildcard can be used per origin.
	// Default value is ["*"]
	AllowedOrigins []string
	// AllowOriginFunc is a custom function to validate the origin. It take the origin
	// as argument and returns true if allowed or false otherwise. If this option is
	// set, the content of AllowedOrigins is ignored.
	AllowOriginFunc func(origin string) bool
	// AllowOriginFunc is a custom function to validate the origin. It takes the HTTP Request object and the origin as
	// argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins`
	// and `AllowOriginFunc` is ignored.
	AllowOriginRequestFunc func(r *http.Request, origin string) bool
	// AllowedMethods is a list of methods the client is allowed to use with
	// cross-domain requests. Default value is simple methods (HEAD, GET and POST).
	AllowedMethods []string
	// AllowedHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests.
	// If the special "*" value is present in the list, all headers will be allowed.
	// Default value is [] but "Origin" is always appended to the list.
	AllowedHeaders []string
	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposedHeaders []string
	// MaxAge indicates how long (in seconds) the results of a preflight request
	// can be cached
	MaxAge int
	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool
	// OptionsPassthrough instructs preflight to let other potential next handlers to
	// process the OPTIONS method. Turn this on if your application handles OPTIONS.
	OptionsPassthrough bool
	// Debugging flag adds additional output to debug server side CORS issues
	Debug bool
}

CORSOptions is a configuration container to setup the CORS middleware.

type HTTPServer

type HTTPServer struct {
	Server
	// contains filtered or unexported fields
}

HTTPServer is responsible for exposing the collection of the services as a single HTTP server

func New

func New(
	version string,
	ipaddr string,
	httpConfig HTTPServerConfig,
	tlsConfig *tls.Config,
) (*HTTPServer, error)

New creates a new instance of the server

func (*HTTPServer) AddService

func (server *HTTPServer) AddService(s Service)

AddService provides a service registration for the server

func (*HTTPServer) Audit

func (server *HTTPServer) Audit(source string,
	eventType string,
	identity string,
	contextID string,
	raftIndex uint64,
	message string)

Audit create an audit event

func (*HTTPServer) HTTPConfig

func (server *HTTPServer) HTTPConfig() HTTPServerConfig

HTTPConfig returns HTTPServerConfig

func (*HTTPServer) HostName

func (server *HTTPServer) HostName() string

HostName returns the host name of the server

func (*HTTPServer) IsReady

func (server *HTTPServer) IsReady() bool

IsReady returns true when the server is ready to serve

func (*HTTPServer) LocalIP

func (server *HTTPServer) LocalIP() string

LocalIP returns the IP address of the server

func (*HTTPServer) Name

func (server *HTTPServer) Name() string

Name returns the server name

func (*HTTPServer) NewMux

func (server *HTTPServer) NewMux() http.Handler

NewMux creates a new http handler for the http server, typically you only need to call this directly for tests.

func (*HTTPServer) OnEvent

func (server *HTTPServer) OnEvent(evt ServerEvent, handler ServerEventFunc)

OnEvent accepts a callback to handle server events

func (*HTTPServer) Port

func (server *HTTPServer) Port() string

Port returns the port name of the server

func (*HTTPServer) Protocol

func (server *HTTPServer) Protocol() string

Protocol returns the protocol

func (*HTTPServer) Scheduler

func (server *HTTPServer) Scheduler() tasks.Scheduler

Scheduler returns task scheduler for the server

func (*HTTPServer) ServeHTTP

func (server *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP should write reply headers and data to the ResponseWriter and then return. Returning signals that the request is finished; it is not valid to use the ResponseWriter or read from the Request.Body after or concurrently with the completion of the ServeHTTP call.

func (*HTTPServer) Service

func (server *HTTPServer) Service(name string) Service

Service returns a registered server

func (*HTTPServer) StartHTTP

func (server *HTTPServer) StartHTTP() error

StartHTTP will verify all the TLS related files are present and start the actual HTTPS listener for the server

func (*HTTPServer) StartedAt

func (server *HTTPServer) StartedAt() time.Time

StartedAt returns the time when the server started

func (*HTTPServer) StopHTTP

func (server *HTTPServer) StopHTTP()

StopHTTP will perform a graceful shutdown of the serivce by

  1. signally to the Load Balancer to remove this instance from the pool by changing to response to /availability
  2. cause new responses to have their Connection closed when finished to force clients to re-connect [hopefully to a different instance]
  3. wait the minShutdownTime to ensure the LB has noticed the status change
  4. wait for existing requests to finish processing
  5. step 4 is capped by a overrall timeout where we'll give up waiting for the requests to complete and will exit.

it is expected that you don't try and use the server instance again after this. [i.e. if you want to start it again, create another server instance]

func (*HTTPServer) TLSConfig

func (server *HTTPServer) TLSConfig() *tls.Config

TLSConfig returns TLSConfig

func (*HTTPServer) Uptime

func (server *HTTPServer) Uptime() time.Duration

Uptime returns the duration the server was up

func (*HTTPServer) Version

func (server *HTTPServer) Version() string

Version returns the version of the server

func (*HTTPServer) WithAuditor added in v0.5.0

func (server *HTTPServer) WithAuditor(auditor Auditor) *HTTPServer

WithAuditor enables to use auditor

func (*HTTPServer) WithAuthz added in v0.5.0

func (server *HTTPServer) WithAuthz(authz authz.HTTPAuthz) *HTTPServer

WithAuthz enables to use Authz

func (*HTTPServer) WithCORS

func (server *HTTPServer) WithCORS(cors *CORSOptions) *HTTPServer

WithCORS enables CORS options

func (*HTTPServer) WithIdentityProvider added in v0.7.0

func (server *HTTPServer) WithIdentityProvider(provider identity.ProviderFromRequest) *HTTPServer

WithIdentityProvider enables to set idenity on each request

func (*HTTPServer) WithMuxFactory

func (server *HTTPServer) WithMuxFactory(muxFactory MuxFactory)

WithMuxFactory requires the server to use `muxFactory` to create server handler.

func (*HTTPServer) WithScheduler added in v0.5.0

func (server *HTTPServer) WithScheduler(scheduler tasks.Scheduler) *HTTPServer

WithScheduler enables to schedule tasks, such as heartbeat, uptime etc If a scheduler is not provided, then tasks will not be schedduled.

func (*HTTPServer) WithShutdownTimeout added in v0.5.0

func (server *HTTPServer) WithShutdownTimeout(timeout time.Duration) *HTTPServer

WithShutdownTimeout sets the connection draining timeouts on server shutdown

type HTTPServerConfig

type HTTPServerConfig interface {
	// ServiceName specifies name of the service: HTTP|HTTPS|WebAPI
	GetServiceName() string
	// Disabled specifies if the service is disabled
	GetDisabled() bool
	// VIPName is the FQ name of the VIP to the cluster [this is used when building the cert requests]
	GetVIPName() string
	// BindAddr is the address that the HTTPS service should be exposed on
	GetBindAddr() string
	// PackageLogger if set, specifies name of the package logger
	GetPackageLogger() string
	// AllowProfiling if set, will allow for per request CPU/Memory profiling triggered by the URI QueryString
	GetAllowProfiling() bool
	// ProfilerDir specifies the directories where per-request profile information is written, if not set will write to a TMP dir
	GetProfilerDir() string
	// Services is a list of services to enable for this HTTP Service
	GetServices() []string
	// HeartbeatSecs specifies heartbeat GetHeartbeatSecserval in seconds [30 secs is a minimum]
	GetHeartbeatSecs() int
}

HTTPServerConfig contains the configuration of the HTTPS API Service

type Handle

type Handle func(http.ResponseWriter, *http.Request, Params)

Handle is a function that can be registered to a route to handle HTTP requests. Like http.HandlerFunc, but has a third parameter for the values of wildcards (variables).

type MuxFactory

type MuxFactory interface {
	NewMux() http.Handler
}

MuxFactory creates http handlers.

type Params

type Params httprouter.Params

Params is a Param-slice, as returned by the router. The slice is ordered, the first URL parameter is also the first slice value. It is therefore safe to read values by the index.

func (Params) ByName

func (ps Params) ByName(name string) string

ByName returns the value of the first Param which key matches the given name. If no matching Param is found, an empty string is returned.

type Router

type Router interface {
	Handler() http.Handler
	GET(path string, handle Handle)
	HEAD(path string, handle Handle)
	OPTIONS(path string, handle Handle)
	POST(path string, handle Handle)
	PUT(path string, handle Handle)
	PATCH(path string, handle Handle)
	DELETE(path string, handle Handle)
	CONNECT(path string, handle Handle)
}

Router provides a router interface

func NewRouter

func NewRouter(notfoundhandler http.HandlerFunc) Router

NewRouter returns a new initialized Router.

func NewRouterWithCORS

func NewRouterWithCORS(notfoundhandler http.HandlerFunc, opt *CORSOptions) Router

NewRouterWithCORS returns a new initialized Router with CORS enabled

type Server

type Server interface {
	http.Handler
	Name() string
	Version() string
	HostName() string
	LocalIP() string
	Port() string
	Protocol() string
	StartedAt() time.Time
	Uptime() time.Duration
	Service(name string) Service
	HTTPConfig() HTTPServerConfig
	TLSConfig() *tls.Config

	// IsReady indicates that all subservices are ready to serve
	IsReady() bool

	// Audit records an auditable event.
	// 	source indicates the area that the event was triggered by
	// 	eventType indicates the specific event that occured
	// 	identity specifies the identity of the user that triggered this event, typically this is <role>/<cn>
	// 	contextID specifies the request ContextID that the event was triggered in [this can be used for cross service correlation of logs]
	// 	raftIndex indicates the index# of the raft log in RAFT that the event occured in [if applicable]
	// 	message contains any additional information about this event that is eventType specific
	Audit(source string,
		eventType string,
		identity string,
		contextID string,
		raftIndex uint64,
		message string)

	AddService(s Service)
	StartHTTP() error
	StopHTTP()

	Scheduler() tasks.Scheduler

	OnEvent(evt ServerEvent, handler ServerEventFunc)
}

Server is an interface to provide server status

Example
package main

import (
	"crypto/x509"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	metricsutil "github.com/go-phorce/dolly/metrics/util"
	"github.com/go-phorce/dolly/rest"
	"github.com/go-phorce/dolly/rest/tlsconfig"
	"github.com/go-phorce/dolly/tasks"
	"github.com/go-phorce/dolly/testify/auditor"
	"github.com/go-phorce/dolly/xlog"
	"github.com/pkg/errors"
)

var logger = xlog.NewPackageLogger("github.com/go-phorce/dolly", "rest_test")

func main() {
	sigs := make(chan os.Signal, 2)

	tlsCfg := &tlsConfig{
		CertFile:       "testdata/test-server.pem",
		KeyFile:        "testdata/test-server-key.pem",
		TrustedCAFile:  "testdata/test-server-rootca.pem",
		WithClientAuth: false,
	}

	tlsInfo, tlsloader, err := createServerTLSInfo(tlsCfg)
	if err != nil {
		panic("unable to create TLS config")
	}
	defer tlsloader.Close()

	cfg := &serverConfig{
		BindAddr: ":8181",
	}

	scheduler := tasks.NewScheduler()

	server, err := rest.New("v1.0.123", "", cfg, tlsInfo)
	if err != nil {
		panic("unable to create the server")
	}
	server.WithAuditor(auditor.NewInMemory()).
		WithScheduler(scheduler)

	// execute and schedule
	go certExpirationPublisherTask(tlsloader)
	server.Scheduler().Add(tasks.NewTaskAtIntervals(1, tasks.Hours).Do("servertls", certExpirationPublisherTask, tlsloader))

	svc := NewService(server)
	server.AddService(svc)

	fmt.Println("starting server")
	err = server.StartHTTP()
	if err != nil {
		panic("unable to start the server: " + fmt.Sprintf("%+v", err))
	}
	scheduler.Start()

	go func() {
		// Send STOP signal after few seconds,
		// in production the service should listen to
		// os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGUSR2, syscall.SIGABRT events
		time.Sleep(3 * time.Second)
		fmt.Println("sending syscall.SIGTERM signal")
		sigs <- syscall.SIGTERM
	}()

	// register for signals, and wait to be shutdown
	signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGUSR2, syscall.SIGABRT)
	// Block until a signal is received.
	sig := <-sigs

	scheduler.Stop()
	server.StopHTTP()
	fmt.Println("stopped server")

	// SIGUSR2 is triggered by the upstart pre-stop script, we don't want
	// to actually exit the process in that case until upstart sends SIGTERM
	if sig == syscall.SIGUSR2 {
		select {
		case <-time.After(time.Second * 5):
			logger.Info("status='service shutdown from SIGUSR2 complete, waiting for SIGTERM to exit'")
		case sig = <-sigs:
			logger.Infof("status=exiting, reason=received_signal, sig=%v", sig)
		}
	}

}

func certExpirationPublisherTask(tlsloader *tlsconfig.KeypairReloader) {
	certFile, keyFile := tlsloader.CertAndKeyFiles()

	logger.Tracef("cert=%q, key=%q", certFile, keyFile)

	tlsloader.Reload()
	pair := tlsloader.Keypair()
	if pair != nil {
		cert, err := x509.ParseCertificate(pair.Certificate[0])
		if err != nil {
			errors.WithMessagef(err, "reason=unable_parse_tls_cert, file=%q", certFile)
		} else {
			metricsutil.PublishCertExpirationInDays(cert, "server")
		}
	} else {
		logger.Warningf("reason=Keypair, cert=%q, key=%q", certFile, keyFile)
	}
}
Output:

starting server
sending syscall.SIGTERM signal
stopped server

type ServerEvent

type ServerEvent int

ServerEvent specifies server event type

const (
	// ServerStartedEvent is fired on server start
	ServerStartedEvent ServerEvent = iota
	// ServerStoppedEvent is fired after server stopped
	ServerStoppedEvent
	// ServerStoppingEvent is fired before server stopped
	ServerStoppingEvent
)

type ServerEventFunc

type ServerEventFunc func(evt ServerEvent)

ServerEventFunc is a callback to handle server events

type Service

type Service interface {
	Name() string
	Register(Router)
	Close()
	// IsReady indicates that service is ready to serve its end-points
	IsReady() bool
}

Service provides a way for subservices to be registered so they get added to the http API.

type TLSInfoConfig

type TLSInfoConfig interface {
	// GetCertFile returns location of the cert
	GetCertFile() string
	// GetKeyFile returns location of the key
	GetKeyFile() string
	// TrustedCAFile specifies location of the Trusted CA file
	GetTrustedCAFile() string
	// ClientCertAuth controls client auth
	GetClientCertAuth() *bool
}

TLSInfoConfig contains configuration info for the TLS

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL