2020-12-26 13:11:49 +00:00
|
|
|
//go:generate mockgen -source=$GOFILE -destination=./mock/app.mock.go -package=mock
|
|
|
|
|
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
2021-01-13 17:07:04 +00:00
|
|
|
"gitlab.com/inetmock/inetmock/internal/endpoint"
|
2020-12-26 13:11:49 +00:00
|
|
|
"gitlab.com/inetmock/inetmock/pkg/api"
|
2021-01-04 16:52:21 +00:00
|
|
|
"gitlab.com/inetmock/inetmock/pkg/audit"
|
2021-01-13 16:59:08 +00:00
|
|
|
"gitlab.com/inetmock/inetmock/pkg/audit/sink"
|
2020-12-26 13:11:49 +00:00
|
|
|
"gitlab.com/inetmock/inetmock/pkg/cert"
|
|
|
|
"gitlab.com/inetmock/inetmock/pkg/config"
|
|
|
|
"gitlab.com/inetmock/inetmock/pkg/health"
|
|
|
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
|
|
|
"gitlab.com/inetmock/inetmock/pkg/path"
|
2021-01-18 17:35:13 +00:00
|
|
|
"go.uber.org/multierr"
|
2020-12-26 13:11:49 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
configFilePath string
|
|
|
|
logLevel string
|
|
|
|
developmentLogs bool
|
|
|
|
)
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
type contextKey string
|
|
|
|
|
|
|
|
const (
|
|
|
|
loggerKey contextKey = "gitlab.com/inetmock/inetmock/app/context/logger"
|
|
|
|
configKey contextKey = "gitlab.com/inetmock/inetmock/app/context/config"
|
|
|
|
handlerRegistryKey contextKey = "gitlab.com/inetmock/inetmock/app/context/handlerRegistry"
|
|
|
|
healthCheckerKey contextKey = "gitlab.com/inetmock/inetmock/app/context/healthChecker"
|
|
|
|
endpointManagerKey contextKey = "gitlab.com/inetmock/inetmock/app/context/endpointManager"
|
|
|
|
certStoreKey contextKey = "gitlab.com/inetmock/inetmock/app/context/certStore"
|
|
|
|
eventStreamKey contextKey = "gitlab.com/inetmock/inetmock/app/context/eventStream"
|
|
|
|
)
|
|
|
|
|
2020-12-26 13:11:49 +00:00
|
|
|
type App interface {
|
|
|
|
api.PluginContext
|
2021-01-13 20:38:52 +00:00
|
|
|
EventStream() audit.EventStream
|
2020-12-26 13:11:49 +00:00
|
|
|
Config() config.Config
|
|
|
|
Checker() health.Checker
|
2021-01-13 17:07:04 +00:00
|
|
|
EndpointManager() endpoint.EndpointManager
|
2020-12-26 13:11:49 +00:00
|
|
|
HandlerRegistry() api.HandlerRegistry
|
|
|
|
Context() context.Context
|
2021-01-18 17:35:13 +00:00
|
|
|
RootCommand() *cobra.Command
|
2020-12-26 13:11:49 +00:00
|
|
|
MustRun()
|
|
|
|
Shutdown()
|
2021-01-18 17:35:13 +00:00
|
|
|
|
|
|
|
// WithCommands adds subcommands to the root command
|
|
|
|
// requires nothing
|
2020-12-26 13:11:49 +00:00
|
|
|
WithCommands(cmds ...*cobra.Command) App
|
2021-01-18 17:35:13 +00:00
|
|
|
|
|
|
|
// WithHandlerRegistry builds up the handler registry
|
|
|
|
// requires nothing
|
|
|
|
WithHandlerRegistry(registrations ...api.Registration) App
|
|
|
|
|
|
|
|
// WithHealthChecker adds the health checker mechanism
|
|
|
|
// requires nothing
|
|
|
|
WithHealthChecker() App
|
|
|
|
|
|
|
|
// WithLogger configures the logging system
|
|
|
|
// requires nothing
|
|
|
|
WithLogger() App
|
|
|
|
|
|
|
|
// WithEndpointManager creates an endpoint manager instance and adds it to the context
|
|
|
|
// requires WithHandlerRegistry, WithHealthChecker and WithLogger
|
|
|
|
WithEndpointManager() App
|
|
|
|
|
|
|
|
// WithCertStore initializes the cert store
|
|
|
|
// requires WithLogger and WithConfig
|
|
|
|
WithCertStore() App
|
|
|
|
|
|
|
|
// WithEventStream adds the audit event stream
|
|
|
|
// requires WithLogger
|
|
|
|
WithEventStream() App
|
|
|
|
|
|
|
|
// WithConfig loads the config
|
|
|
|
// requires nothing
|
|
|
|
WithConfig() App
|
|
|
|
|
|
|
|
WithInitTasks(task ...func(cmd *cobra.Command, args []string) (err error)) App
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type app struct {
|
2021-01-18 17:35:13 +00:00
|
|
|
rootCmd *cobra.Command
|
|
|
|
ctx context.Context
|
|
|
|
cancel context.CancelFunc
|
|
|
|
lateInitTasks []func(cmd *cobra.Command, args []string) (err error)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *app) MustRun() {
|
|
|
|
if err := a.rootCmd.Execute(); err != nil {
|
2021-01-18 17:35:13 +00:00
|
|
|
if a.Logger() != nil {
|
|
|
|
a.Logger().Error(
|
2020-12-26 13:11:49 +00:00
|
|
|
"Failed to run inetmock",
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) Logger() logging.Logger {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(loggerKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(logging.Logger)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) Config() config.Config {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(configKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(config.Config)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) CertStore() cert.Store {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(certStoreKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(cert.Store)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) Checker() health.Checker {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(healthCheckerKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(health.Checker)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) EndpointManager() endpoint.EndpointManager {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(endpointManagerKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(endpoint.EndpointManager)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) Audit() audit.Emitter {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(eventStreamKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(audit.Emitter)
|
2021-01-04 16:52:21 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) EventStream() audit.EventStream {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(eventStreamKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(audit.EventStream)
|
2021-01-13 20:38:52 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) HandlerRegistry() api.HandlerRegistry {
|
2021-01-26 17:42:07 +00:00
|
|
|
val := a.ctx.Value(handlerRegistryKey)
|
|
|
|
if val == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return val.(api.HandlerRegistry)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) Context() context.Context {
|
2020-12-26 13:11:49 +00:00
|
|
|
return a.ctx
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
func (a *app) RootCommand() *cobra.Command {
|
|
|
|
return a.rootCmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *app) Shutdown() {
|
2020-12-26 13:11:49 +00:00
|
|
|
a.cancel()
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithCommands adds subcommands to the root command
|
|
|
|
// requires nothing
|
2020-12-26 13:11:49 +00:00
|
|
|
func (a *app) WithCommands(cmds ...*cobra.Command) App {
|
|
|
|
a.rootCmd.AddCommand(cmds...)
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithHandlerRegistry builds up the handler registry
|
|
|
|
// requires nothing
|
|
|
|
func (a *app) WithHandlerRegistry(registrations ...api.Registration) App {
|
2020-12-26 13:11:49 +00:00
|
|
|
registry := api.NewHandlerRegistry()
|
|
|
|
|
|
|
|
for _, registration := range registrations {
|
2021-01-18 17:35:13 +00:00
|
|
|
if err := registration(registry); err != nil {
|
|
|
|
panic(err)
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
a.ctx = context.WithValue(a.ctx, handlerRegistryKey, registry)
|
2020-12-26 13:11:49 +00:00
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
return a
|
|
|
|
}
|
2020-12-26 13:11:49 +00:00
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithHealthChecker adds the health checker mechanism
|
|
|
|
// requires nothing
|
|
|
|
func (a *app) WithHealthChecker() App {
|
|
|
|
checker := health.New()
|
|
|
|
a.ctx = context.WithValue(a.ctx, healthCheckerKey, checker)
|
|
|
|
return a
|
|
|
|
}
|
2020-12-26 13:11:49 +00:00
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithLogger configures the logging system
|
|
|
|
// requires nothing
|
|
|
|
func (a *app) WithLogger() App {
|
|
|
|
a.lateInitTasks = append(a.lateInitTasks, func(cmd *cobra.Command, args []string) (err error) {
|
2020-12-26 13:11:49 +00:00
|
|
|
logging.ConfigureLogging(
|
|
|
|
logging.ParseLevel(logLevel),
|
|
|
|
developmentLogs,
|
|
|
|
map[string]interface{}{
|
2021-01-18 17:35:13 +00:00
|
|
|
"cwd": path.WorkingDirectory(),
|
|
|
|
"cmd": cmd.Name(),
|
|
|
|
"args": args,
|
2020-12-26 13:11:49 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
var logger logging.Logger
|
|
|
|
if logger, err = logging.CreateLogger(); err != nil {
|
2020-12-26 13:11:49 +00:00
|
|
|
return
|
|
|
|
}
|
2021-01-18 17:35:13 +00:00
|
|
|
a.ctx = context.WithValue(a.ctx, loggerKey, logger)
|
|
|
|
return
|
|
|
|
})
|
|
|
|
return a
|
|
|
|
}
|
2020-12-26 13:11:49 +00:00
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithEndpointManager creates an endpoint manager instance and adds it to the context
|
|
|
|
// requires WithHandlerRegistry, WithHealthChecker and WithLogger
|
|
|
|
func (a *app) WithEndpointManager() App {
|
|
|
|
a.lateInitTasks = append(a.lateInitTasks, func(_ *cobra.Command, _ []string) (err error) {
|
|
|
|
epMgr := endpoint.NewEndpointManager(
|
|
|
|
a.HandlerRegistry(),
|
2021-01-04 16:52:21 +00:00
|
|
|
a.Logger().Named("EndpointManager"),
|
2021-01-18 17:35:13 +00:00
|
|
|
a.Checker(),
|
2021-01-04 16:52:21 +00:00
|
|
|
a,
|
|
|
|
)
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
a.ctx = context.WithValue(a.ctx, endpointManagerKey, epMgr)
|
|
|
|
return
|
|
|
|
})
|
|
|
|
return a
|
|
|
|
}
|
2020-12-26 13:11:49 +00:00
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithCertStore initializes the cert store
|
|
|
|
// requires WithLogger and WithConfig
|
|
|
|
func (a *app) WithCertStore() App {
|
|
|
|
a.lateInitTasks = append(a.lateInitTasks, func(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
var certStore cert.Store
|
|
|
|
if certStore, err = cert.NewDefaultStore(
|
|
|
|
a.Config(),
|
|
|
|
a.Logger().Named("CertStore"),
|
|
|
|
); err != nil {
|
2020-12-26 13:11:49 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
a.ctx = context.WithValue(a.ctx, certStoreKey, certStore)
|
|
|
|
return
|
|
|
|
})
|
|
|
|
return a
|
|
|
|
}
|
2021-01-04 16:52:21 +00:00
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
// WithEventStream adds the audit event stream
|
|
|
|
// requires WithLogger
|
|
|
|
func (a *app) WithEventStream() App {
|
|
|
|
a.lateInitTasks = append(a.lateInitTasks, func(_ *cobra.Command, _ []string) (err error) {
|
|
|
|
var eventStream audit.EventStream
|
|
|
|
eventStream, err = audit.NewEventStream(
|
2021-01-04 16:52:21 +00:00
|
|
|
a.Logger().Named("EventStream"),
|
|
|
|
audit.WithSinkBufferSize(10),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2020-12-26 13:11:49 +00:00
|
|
|
|
2021-01-26 17:50:53 +00:00
|
|
|
if err = eventStream.RegisterSink(a.ctx, sink.NewLogSink(a.Logger().Named("LogSink"))); err != nil {
|
2021-01-18 17:35:13 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-01-26 18:00:46 +00:00
|
|
|
var metricSink audit.Sink
|
|
|
|
if metricSink, err = sink.NewMetricSink(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = eventStream.RegisterSink(a.ctx, metricSink); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
a.ctx = context.WithValue(a.ctx, eventStreamKey, eventStream)
|
|
|
|
return
|
|
|
|
})
|
|
|
|
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithConfig loads the config
|
|
|
|
// requires nothing
|
|
|
|
func (a *app) WithConfig() App {
|
|
|
|
a.lateInitTasks = append(a.lateInitTasks, func(cmd *cobra.Command, _ []string) (err error) {
|
|
|
|
cfg := config.CreateConfig(cmd.Flags())
|
|
|
|
if err = cfg.ReadConfig(configFilePath); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
a.ctx = context.WithValue(a.ctx, configKey, cfg)
|
2020-12-26 13:11:49 +00:00
|
|
|
return
|
2021-01-18 17:35:13 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *app) WithInitTasks(task ...func(cmd *cobra.Command, args []string) (err error)) App {
|
|
|
|
a.lateInitTasks = append(a.lateInitTasks, task...)
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewApp(name, short string) App {
|
|
|
|
ctx, cancel := initAppContext()
|
|
|
|
a := &app{
|
|
|
|
rootCmd: &cobra.Command{
|
|
|
|
Use: name,
|
|
|
|
Short: short,
|
|
|
|
},
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 17:35:13 +00:00
|
|
|
a.rootCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "Path to config file that should be used")
|
|
|
|
a.rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "logging level to use")
|
|
|
|
a.rootCmd.PersistentFlags().BoolVar(&developmentLogs, "development-logs", false, "Enable development mode logs")
|
|
|
|
|
|
|
|
a.rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
for _, initTask := range a.lateInitTasks {
|
|
|
|
err = multierr.Append(err, initTask(cmd, args))
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return a
|
2020-12-26 13:11:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func initAppContext() (context.Context, context.CancelFunc) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
signals := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-signals
|
|
|
|
cancel()
|
|
|
|
}()
|
|
|
|
|
|
|
|
return ctx, cancel
|
|
|
|
}
|