From 0138b5778251546328845c9095d528e4d58bde28 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Mon, 18 Jan 2021 18:35:13 +0100 Subject: [PATCH] Merged CLI and server app init --- api/proto/internal/rpc/audit.proto | 7 + cmd/imctl/audit_file.go | 15 +- cmd/imctl/audit_watch.go | 4 +- cmd/imctl/cli.go | 75 --------- cmd/imctl/endpoints.go | 2 +- cmd/imctl/handlers.go | 2 +- cmd/imctl/main.go | 61 ++++++- cmd/inetmock/main.go | 35 ++-- go.mod | 1 + internal/app/app.go | 249 ++++++++++++++++++++++------- internal/rpc/audit_server.go | 16 +- 11 files changed, 302 insertions(+), 165 deletions(-) delete mode 100644 cmd/imctl/cli.go diff --git a/api/proto/internal/rpc/audit.proto b/api/proto/internal/rpc/audit.proto index 2eb4a15..7494a5c 100644 --- a/api/proto/internal/rpc/audit.proto +++ b/api/proto/internal/rpc/audit.proto @@ -9,12 +9,19 @@ import 'pkg/audit/event_entity.proto'; package inetmock.rpc; +enum FileOpenMode { + TRUNCATE = 0; + APPEND = 1; +} + message WatchEventsRequest { string watcherName = 1; } message RegisterFileSinkRequest { string targetPath = 1; + FileOpenMode openMode = 2; + uint32 permissions = 3; } message RegisterFileSinkResponse { diff --git a/cmd/imctl/audit_file.go b/cmd/imctl/audit_file.go index f34e4c2..132067f 100644 --- a/cmd/imctl/audit_file.go +++ b/cmd/imctl/audit_file.go @@ -24,6 +24,13 @@ var ( Args: cobra.ExactArgs(1), RunE: runRemoveFile, } + + readFileCmd = &cobra.Command{ + Use: "readFile", + Short: "reads an audit file and prints the events", + Args: cobra.ExactArgs(1), + RunE: runReadFile, + } ) func runAddFile(_ *cobra.Command, args []string) (err error) { @@ -35,7 +42,7 @@ func runAddFile(_ *cobra.Command, args []string) (err error) { } auditClient := rpc.NewAuditClient(conn) - ctx, cancel := context.WithTimeout(appCtx, grpcTimeout) + ctx, cancel := context.WithTimeout(cliApp.Context(), grpcTimeout) defer cancel() _, err = auditClient.RegisterFileSink(ctx, &rpc.RegisterFileSinkRequest{TargetPath: args[0]}) @@ -44,9 +51,13 @@ func runAddFile(_ *cobra.Command, args []string) (err error) { func runRemoveFile(_ *cobra.Command, args []string) (err error) { auditClient := rpc.NewAuditClient(conn) - ctx, cancel := context.WithTimeout(appCtx, grpcTimeout) + ctx, cancel := context.WithTimeout(cliApp.Context(), grpcTimeout) defer cancel() _, err = auditClient.RemoveFileSink(ctx, &rpc.RemoveFileSinkRequest{TargetPath: args[0]}) return } + +func runReadFile(_ *cobra.Command, args []string) (err error) { + return +} diff --git a/cmd/imctl/audit_watch.go b/cmd/imctl/audit_watch.go index 8bce566..42f4345 100644 --- a/cmd/imctl/audit_watch.go +++ b/cmd/imctl/audit_watch.go @@ -29,7 +29,7 @@ func watchAuditEvents(_ *cobra.Command, _ []string) (err error) { auditClient := rpc.NewAuditClient(conn) var watchClient rpc.Audit_WatchEventsClient - if watchClient, err = auditClient.WatchEvents(appCtx, &rpc.WatchEventsRequest{WatcherName: listenerName}); err != nil { + if watchClient, err = auditClient.WatchEvents(cliApp.Context(), &rpc.WatchEventsRequest{WatcherName: listenerName}); err != nil { fmt.Println(err.Error()) os.Exit(1) } @@ -47,7 +47,7 @@ func watchAuditEvents(_ *cobra.Command, _ []string) (err error) { } }() - <-appCtx.Done() + <-cliApp.Context().Done() err = watchClient.CloseSend() return diff --git a/cmd/imctl/cli.go b/cmd/imctl/cli.go deleted file mode 100644 index a06057f..0000000 --- a/cmd/imctl/cli.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - "context" - "os" - "os/signal" - "os/user" - "syscall" - "time" - - "github.com/google/uuid" - "github.com/spf13/cobra" - "google.golang.org/grpc" -) - -var ( - cliCmd = &cobra.Command{ - Use: "", - Short: "IMCTL is the CLI app to interact with an INetMock server", - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - return initGRPCConnection() - }, - } - - inetMockSocketPath string - outputFormat string - grpcTimeout time.Duration - appCtx context.Context - appCancel context.CancelFunc - conn *grpc.ClientConn -) - -func init() { - cliCmd.PersistentFlags().StringVar(&inetMockSocketPath, "socket-path", "unix:///var/run/inetmock.sock", "Path to the INetMock socket file") - cliCmd.PersistentFlags().StringVarP(&outputFormat, "format", "f", "table", "Output format to use. Possible values: table, json, yaml") - cliCmd.PersistentFlags().DurationVar(&grpcTimeout, "grpc-timeout", 5*time.Second, "Timeout to connect to the gRPC API") - - cliCmd.AddCommand(endpointsCmd, handlerCmd, healthCmd, auditCmd) - endpointsCmd.AddCommand(getEndpoints) - handlerCmd.AddCommand(getHandlersCmd) - healthCmd.AddCommand(generalHealthCmd, containerHealthCmd) - - currentUser := "" - if usr, err := user.Current(); err == nil { - currentUser = usr.Username - } else { - currentUser = uuid.New().String() - } - - watchEventsCmd.PersistentFlags().StringVar( - &listenerName, - "listener-name", - currentUser, - "set listener name - defaults to the current username, if the user cannot be determined a random UUID will be used", - ) - auditCmd.AddCommand(watchEventsCmd, addFileCmd, removeFileCmd) -} - -func initGRPCConnection() (err error) { - appCtx, appCancel = context.WithCancel(context.Background()) - - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - - go func() { - <-signals - appCancel() - }() - - dialCtx, cancel := context.WithTimeout(appCtx, grpcTimeout) - conn, err = grpc.DialContext(dialCtx, inetMockSocketPath, grpc.WithInsecure()) - cancel() - - return -} diff --git a/cmd/imctl/endpoints.go b/cmd/imctl/endpoints.go index 997164d..592ef9b 100644 --- a/cmd/imctl/endpoints.go +++ b/cmd/imctl/endpoints.go @@ -51,7 +51,7 @@ func fromEndpoints(eps []*rpc.Endpoint) (out []*printableEndpoint) { func runGetEndpoints(_ *cobra.Command, _ []string) (err error) { endpointsClient := rpc.NewEndpointsClient(conn) - ctx, cancel := context.WithTimeout(appCtx, grpcTimeout) + ctx, cancel := context.WithTimeout(cliApp.Context(), grpcTimeout) defer cancel() var endpointsResp *rpc.GetEndpointsResponse if endpointsResp, err = endpointsClient.GetEndpoints(ctx, &rpc.GetEndpointsRequest{}); err != nil { diff --git a/cmd/imctl/handlers.go b/cmd/imctl/handlers.go index 7672e26..06822da 100644 --- a/cmd/imctl/handlers.go +++ b/cmd/imctl/handlers.go @@ -40,7 +40,7 @@ func fromHandlers(hs []string) (handlers []*printableHandler) { func runGetHandlers(_ *cobra.Command, _ []string) { handlersClient := rpc.NewHandlersClient(conn) - ctx, cancel := context.WithTimeout(appCtx, grpcTimeout) + ctx, cancel := context.WithTimeout(cliApp.Context(), grpcTimeout) defer cancel() var err error var handlersResp *rpc.GetHandlersResponse diff --git a/cmd/imctl/main.go b/cmd/imctl/main.go index 822594e..1ca965f 100644 --- a/cmd/imctl/main.go +++ b/cmd/imctl/main.go @@ -1,8 +1,63 @@ package main +import ( + "context" + "os/user" + "time" + + "github.com/google/uuid" + "github.com/spf13/cobra" + "gitlab.com/inetmock/inetmock/internal/app" + "google.golang.org/grpc" +) + +var ( + inetMockSocketPath string + outputFormat string + grpcTimeout time.Duration + cliApp app.App + conn *grpc.ClientConn +) + func main() { - defer appCancel() - if err := cliCmd.Execute(); err != nil { - panic(err) + + endpointsCmd.AddCommand(getEndpoints) + handlerCmd.AddCommand(getHandlersCmd) + healthCmd.AddCommand(generalHealthCmd, containerHealthCmd) + + cliApp = app.NewApp("imctl", "IMCTL is the CLI app to interact with an INetMock server"). + WithCommands(endpointsCmd, handlerCmd, healthCmd, auditCmd). + WithInitTasks(func(_ *cobra.Command, _ []string) (err error) { + return initGRPCConnection() + }) + + cliApp.RootCommand().PersistentFlags().StringVar(&inetMockSocketPath, "socket-path", "unix:///var/run/inetmock.sock", "Path to the INetMock socket file") + cliApp.RootCommand().PersistentFlags().StringVarP(&outputFormat, "format", "f", "table", "Output format to use. Possible values: table, json, yaml") + cliApp.RootCommand().PersistentFlags().DurationVar(&grpcTimeout, "grpc-timeout", 5*time.Second, "Timeout to connect to the gRPC API") + + currentUser := "" + if usr, err := user.Current(); err == nil { + currentUser = usr.Username + } else { + currentUser = uuid.New().String() } + + watchEventsCmd.PersistentFlags().StringVar( + &listenerName, + "listener-name", + currentUser, + "set listener name - defaults to the current username, if the user cannot be determined a random UUID will be used", + ) + auditCmd.AddCommand(watchEventsCmd, addFileCmd, removeFileCmd) + + cliApp.MustRun() + +} + +func initGRPCConnection() (err error) { + dialCtx, cancel := context.WithTimeout(cliApp.Context(), grpcTimeout) + conn, err = grpc.DialContext(dialCtx, inetMockSocketPath, grpc.WithInsecure()) + cancel() + + return } diff --git a/cmd/inetmock/main.go b/cmd/inetmock/main.go index 50f9009..bcec3ca 100644 --- a/cmd/inetmock/main.go +++ b/cmd/inetmock/main.go @@ -2,19 +2,13 @@ package main import ( "fmt" - "os" "gitlab.com/inetmock/inetmock/internal/app" - "gitlab.com/inetmock/inetmock/internal/endpoint/handler/dns/mock" - _ "gitlab.com/inetmock/inetmock/internal/endpoint/handler/dns/mock" - _ "gitlab.com/inetmock/inetmock/internal/endpoint/handler/http/mock" - mock2 "gitlab.com/inetmock/inetmock/internal/endpoint/handler/http/mock" + dns "gitlab.com/inetmock/inetmock/internal/endpoint/handler/dns/mock" + http "gitlab.com/inetmock/inetmock/internal/endpoint/handler/http/mock" "gitlab.com/inetmock/inetmock/internal/endpoint/handler/http/proxy" - _ "gitlab.com/inetmock/inetmock/internal/endpoint/handler/http/proxy" "gitlab.com/inetmock/inetmock/internal/endpoint/handler/metrics" - _ "gitlab.com/inetmock/inetmock/internal/endpoint/handler/metrics" "gitlab.com/inetmock/inetmock/internal/endpoint/handler/tls/interceptor" - _ "gitlab.com/inetmock/inetmock/internal/endpoint/handler/tls/interceptor" "go.uber.org/zap" ) @@ -30,18 +24,19 @@ func main() { } }() - var err error - if server, err = app.NewApp( - mock2.AddHTTPMock, - mock.AddDNSMock, - interceptor.AddTLSInterceptor, - proxy.AddHTTPProxy, - metrics.AddMetricsExporter, - ); err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - server. + app.NewApp("inetmock", "INetMock is lightweight internet mock"). + WithHandlerRegistry( + http.AddHTTPMock, + dns.AddDNSMock, + interceptor.AddTLSInterceptor, + proxy.AddHTTPProxy, + metrics.AddMetricsExporter). WithCommands(serveCmd, generateCaCmd). + WithConfig(). + WithLogger(). + WithHealthChecker(). + WithCertStore(). + WithEventStream(). + WithEndpointManager(). MustRun() } diff --git a/go.mod b/go.mod index 993562b..aff09f2 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.1 + go.uber.org/multierr v1.5.0 go.uber.org/zap v1.16.0 google.golang.org/grpc v1.34.0 google.golang.org/protobuf v1.25.0 diff --git a/internal/app/app.go b/internal/app/app.go index 3540e6c..1a8b6db 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -18,6 +18,7 @@ import ( "gitlab.com/inetmock/inetmock/pkg/health" "gitlab.com/inetmock/inetmock/pkg/logging" "gitlab.com/inetmock/inetmock/pkg/path" + "go.uber.org/multierr" "go.uber.org/zap" ) @@ -27,6 +28,18 @@ var ( developmentLogs bool ) +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" +) + type App interface { api.PluginContext EventStream() audit.EventStream @@ -35,28 +48,56 @@ type App interface { EndpointManager() endpoint.EndpointManager HandlerRegistry() api.HandlerRegistry Context() context.Context + RootCommand() *cobra.Command MustRun() Shutdown() + + // WithCommands adds subcommands to the root command + // requires nothing WithCommands(cmds ...*cobra.Command) App + + // 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 } type app struct { - cfg config.Config - rootCmd *cobra.Command - rootLogger logging.Logger - certStore cert.Store - checker health.Checker - endpointManager endpoint.EndpointManager - registry api.HandlerRegistry - ctx context.Context - cancel context.CancelFunc - eventStream audit.EventStream + rootCmd *cobra.Command + ctx context.Context + cancel context.CancelFunc + lateInitTasks []func(cmd *cobra.Command, args []string) (err error) } func (a *app) MustRun() { if err := a.rootCmd.Execute(); err != nil { - if a.rootLogger != nil { - a.rootLogger.Error( + if a.Logger() != nil { + a.Logger().Error( "Failed to run inetmock", zap.Error(err), ) @@ -66,107 +107,146 @@ func (a *app) MustRun() { } } -func (a app) Logger() logging.Logger { - return a.rootLogger +func (a *app) Logger() logging.Logger { + return a.ctx.Value(loggerKey).(logging.Logger) } -func (a app) Config() config.Config { - return a.cfg +func (a *app) Config() config.Config { + return a.ctx.Value(configKey).(config.Config) } -func (a app) CertStore() cert.Store { - return a.certStore +func (a *app) CertStore() cert.Store { + return a.ctx.Value(certStoreKey).(cert.Store) } -func (a app) Checker() health.Checker { - return a.checker +func (a *app) Checker() health.Checker { + return a.ctx.Value(healthCheckerKey).(health.Checker) } -func (a app) EndpointManager() endpoint.EndpointManager { - return a.endpointManager +func (a *app) EndpointManager() endpoint.EndpointManager { + return a.ctx.Value(endpointManagerKey).(endpoint.EndpointManager) } -func (a app) Audit() audit.Emitter { - return a.eventStream +func (a *app) Audit() audit.Emitter { + return a.ctx.Value(eventStreamKey).(audit.Emitter) } -func (a app) EventStream() audit.EventStream { - return a.eventStream +func (a *app) EventStream() audit.EventStream { + return a.ctx.Value(eventStreamKey).(audit.EventStream) } -func (a app) HandlerRegistry() api.HandlerRegistry { - return a.registry +func (a *app) HandlerRegistry() api.HandlerRegistry { + return a.ctx.Value(handlerRegistryKey).(api.HandlerRegistry) } -func (a app) Context() context.Context { +func (a *app) Context() context.Context { return a.ctx } -func (a app) Shutdown() { +func (a *app) RootCommand() *cobra.Command { + return a.rootCmd +} + +func (a *app) Shutdown() { a.cancel() } +// WithCommands adds subcommands to the root command +// requires nothing func (a *app) WithCommands(cmds ...*cobra.Command) App { a.rootCmd.AddCommand(cmds...) return a } -func NewApp(registrations ...api.Registration) (inetmockApp App, err error) { +// WithHandlerRegistry builds up the handler registry +// requires nothing +func (a *app) WithHandlerRegistry(registrations ...api.Registration) App { registry := api.NewHandlerRegistry() for _, registration := range registrations { - if err = registration(registry); err != nil { - return + if err := registration(registry); err != nil { + panic(err) } } - ctx, cancel := initAppContext() + a.ctx = context.WithValue(a.ctx, handlerRegistryKey, registry) - a := &app{ - rootCmd: &cobra.Command{ - Short: "INetMock is lightweight internet mock", - }, - checker: health.New(), - registry: registry, - ctx: ctx, - cancel: cancel, - } + return a +} - 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") +// 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 +} - a.rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) (err error) { +// 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) { logging.ConfigureLogging( logging.ParseLevel(logLevel), developmentLogs, map[string]interface{}{ - "cwd": path.WorkingDirectory(), + "cwd": path.WorkingDirectory(), + "cmd": cmd.Name(), + "args": args, }, ) - if a.rootLogger, err = logging.CreateLogger(); err != nil { + var logger logging.Logger + if logger, err = logging.CreateLogger(); err != nil { return } + a.ctx = context.WithValue(a.ctx, loggerKey, logger) + return + }) + return a +} - a.endpointManager = endpoint.NewEndpointManager( - a.registry, +// 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(), a.Logger().Named("EndpointManager"), - a.checker, + a.Checker(), a, ) - a.cfg = config.CreateConfig(cmd.Flags()) + a.ctx = context.WithValue(a.ctx, endpointManagerKey, epMgr) + return + }) + return a +} - if err = a.cfg.ReadConfig(configFilePath); err != nil { +// 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 { return } - if a.certStore, err = cert.NewDefaultStore(a.cfg, a.rootLogger); err != nil { - return - } + a.ctx = context.WithValue(a.ctx, certStoreKey, certStore) + return + }) + return a +} - a.eventStream, err = audit.NewEventStream( +// 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( a.Logger().Named("EventStream"), audit.WithSinkBufferSize(10), ) @@ -174,11 +254,60 @@ func NewApp(registrations ...api.Registration) (inetmockApp App, err error) { return } - err = a.eventStream.RegisterSink(sink.NewLogSink(a.Logger().Named("LogSink"))) + if err = eventStream.RegisterSink(sink.NewLogSink(a.Logger().Named("LogSink"))); err != nil { + return + } + + 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) + return + }) + + 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, + } + + 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, nil + return a } func initAppContext() (context.Context, context.CancelFunc) { diff --git a/internal/rpc/audit_server.go b/internal/rpc/audit_server.go index 7cb59d2..96bdc63 100644 --- a/internal/rpc/audit_server.go +++ b/internal/rpc/audit_server.go @@ -36,7 +36,21 @@ func (a *auditServer) WatchEvents(req *WatchEventsRequest, srv Audit_WatchEvents func (a *auditServer) RegisterFileSink(_ context.Context, req *RegisterFileSinkRequest) (resp *RegisterFileSinkResponse, err error) { var writer io.WriteCloser - if writer, err = os.OpenFile(req.TargetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err != nil { + var flags int + + switch req.OpenMode { + case FileOpenMode_APPEND: + flags = os.O_CREATE | os.O_WRONLY | os.O_APPEND + default: + flags = os.O_CREATE | os.O_WRONLY | os.O_TRUNC + } + + var permissions = os.FileMode(req.Permissions) + if permissions == 0 { + permissions = 644 + } + + if writer, err = os.OpenFile(req.TargetPath, flags, permissions); err != nil { return } if err = a.eventStream.RegisterSink(sink.NewWriterSink(req.TargetPath, audit.NewEventWriter(writer))); err != nil {