141 lines
4.1 KiB
Go

package server
import (
"context"
"net"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
"github.com/oklog/run"
"google.golang.org/grpc"
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
)
// mockery -all -case underscore -dir ./gen -output ./gen/mocks
// Run initializes and starts the server. This will block until the server
// exits (by cancelling the associated context set with WithContext or due
// to an unrecoverable error).
func Run(opts ...Option) error {
var cfg options
for _, opt := range opts {
opt(&cfg)
}
// Set defaults
if cfg.Context == nil {
cfg.Context = context.Background()
}
if cfg.Logger == nil {
cfg.Logger = hclog.L()
}
// Setup our run group since we're going to be starting multiple
// goroutines for all the servers that we want to live/die as a group.
var group run.Group
// We first add an actor that just returns when the context ends. This
// will trigger the rest of the group to end since a group will not exit
// until any of its actors exit.
ctx, cancelCtx := context.WithCancel(cfg.Context)
cfg.Context = ctx
group.Add(func() error {
<-ctx.Done()
return ctx.Err()
}, func(error) { cancelCtx() })
// Setup our gRPC server.
if err := grpcInit(&group, &cfg); err != nil {
return err
}
// Setup our HTTP server.
if err := httpInit(&group, &cfg); err != nil {
return err
}
// Run!
return group.Run()
}
// Option configures Run
type Option func(*options)
// options configure a server and are set by users only using the exported
// Option functions.
type options struct {
// Context is the context to use for the server. When this is cancelled,
// the server will be gracefully shutdown.
Context context.Context
// Logger is the logger to use. This will default to hclog.L() if not set.
Logger hclog.Logger
// Service is the backend service implementation to use for the server.
Service vagrant_server.VagrantServer
// Client to connect to single Ruby Server runtime process
RubyVagrant *plugin.Client
// Extra services to enable on the server
GRPCServices []func(*grpc.Server)
// GRPCListener will setup the gRPC server. If this is nil, then a
// random loopback port will be chosen. The gRPC server must run since it
// serves the HTTP endpoints as well.
GRPCListener net.Listener
// HTTPListener will setup the HTTP server. If this is nil, then
// the HTTP-based API will be disabled.
HTTPListener net.Listener
// AuthChecker, if set, activates authentication checking on the server.
AuthChecker AuthChecker
// BrowserUIEnabled determines if the browser UI should be mounted
BrowserUIEnabled bool
grpcServer *grpc.Server
}
// WithContext sets the context for the server. When this context is cancelled,
// the server will be shut down.
func WithContext(ctx context.Context) Option {
return func(opts *options) { opts.Context = ctx }
}
// WithLogger sets the logger.
func WithLogger(log hclog.Logger) Option {
return func(opts *options) { opts.Logger = log }
}
// WithGRPC sets the GRPC listener. This listener must be closed manually
// by the caller. Prior to closing the listener, it is recommended that you
// cancel the context set with WithContext and wait for Run to return.
func WithGRPC(ln net.Listener) Option {
return func(opts *options) { opts.GRPCListener = ln }
}
// WithHTTP sets the HTTP listener. This listener must be closed manually
// by the caller. Prior to closing the listener, it is recommended that you
// cancel the context set with WithContext and wait for Run to return.
func WithHTTP(ln net.Listener) Option {
return func(opts *options) { opts.HTTPListener = ln }
}
// WithImpl sets the service implementation to serve.
func WithImpl(impl vagrant_server.VagrantServer) Option {
return func(opts *options) { opts.Service = impl }
}
// WithAuthentication configures the server to require authentication.
func WithAuthentication(ac AuthChecker) Option {
return func(opts *options) { opts.AuthChecker = ac }
}
// WithBrowserUI configures the server to enable the browser UI.
func WithBrowserUI(enabled bool) Option {
return func(opts *options) { opts.BrowserUIEnabled = enabled }
}