storj/cmd/storagenode/internalcmd/cmd_lazy_filewalker.go
Clement Sam b64179c82a {storagenode/pieces,cmd/storagenode}: refactor lazyfilewalker commands and tests
With this change we are directly testing how the command
is executed when the args are passed

Change-Id: Ibb33926014c9d71c928e0fd374bf4edc5a8a1232
2023-06-02 00:11:53 +00:00

169 lines
4.1 KiB
Go

// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
package internalcmd
import (
"context"
"flag"
"fmt"
"io"
"net/url"
"os"
"github.com/spf13/cobra"
"go.uber.org/zap"
"storj.io/private/process"
"storj.io/storj/storagenode/pieces/lazyfilewalker"
"storj.io/storj/storagenode/pieces/lazyfilewalker/execwrapper"
"storj.io/storj/storagenode/storagenodedb"
)
// FilewalkerCfg is the config structure for the lazyfilewalker commands.
type FilewalkerCfg struct {
lazyfilewalker.Config
}
// DatabaseConfig returns the storagenodedb.Config that should be used with this lazyfilewalker.
func (config *FilewalkerCfg) DatabaseConfig() storagenodedb.Config {
return storagenodedb.Config{
Storage: config.Storage,
Info: config.Info,
Info2: config.Info2,
Pieces: config.Pieces,
Filestore: config.Filestore,
Driver: config.Driver,
}
}
// RunOptions defines the options for the lazyfilewalker runners.
type RunOptions struct {
Ctx context.Context
Logger *zap.Logger
config *FilewalkerCfg
stdin io.Reader
stderr io.Writer
stdout io.Writer
}
// LazyFilewalkerCmd is a wrapper for the lazyfilewalker commands.
type LazyFilewalkerCmd struct {
Command *cobra.Command
*RunOptions
}
var _ execwrapper.Command = (*LazyFilewalkerCmd)(nil)
// SetArgs sets arguments for the command.
// The command or executable path should be passed as the first argument.
func (cmd *LazyFilewalkerCmd) SetArgs(args []string) {
if len(args) > 0 {
// arg[0] is the command name or executable path, which we don't need
// args[1] is the lazyfilewalker subcommand.
args = args[2:]
}
cmd.Command.SetArgs(args)
}
// Run runs the LazyFileWalker.
func (cmd *LazyFilewalkerCmd) Run() error {
return cmd.Command.ExecuteContext(cmd.Ctx)
}
// Start starts the LazyFileWalker command, assuming it behaves like the Start method on exec.Cmd.
// This is a no-op and only exists to satisfy the execwrapper.Command interface.
// Wait must be called to actually run the command.
func (cmd *LazyFilewalkerCmd) Start() error {
return nil
}
// Wait waits for the LazyFileWalker to finish, assuming it behaves like the Wait method on exec.Cmd.
func (cmd *LazyFilewalkerCmd) Wait() error {
return cmd.Run()
}
func (r *RunOptions) normalize(cmd *cobra.Command) {
if r.Ctx == nil {
ctx, _ := process.Ctx(cmd)
r.Ctx = ctx
}
if r.stdin == nil {
r.SetIn(os.Stdin)
}
if r.stdout == nil {
r.SetOut(os.Stdout)
}
if r.stderr == nil {
r.SetErr(os.Stderr)
}
if r.Logger == nil {
r.Logger = zap.L()
}
}
// SetIn sets the stdin reader.
func (r *RunOptions) SetIn(reader io.Reader) {
r.stdin = reader
}
// SetOut sets the stdout writer.
func (r *RunOptions) SetOut(writer io.Writer) {
r.stdout = writer
}
// SetErr sets the stderr writer.
func (r *RunOptions) SetErr(writer io.Writer) {
r.stderr = writer
r.tryCreateNewLogger()
}
func (r *RunOptions) tryCreateNewLogger() {
// If the writer is os.Stderr, we don't need to register it because the stderr
// writer is registered by default.
if r.stderr == os.Stderr {
return
}
writerkey := "zapwriter"
err := zap.RegisterSink(writerkey, func(u *url.URL) (zap.Sink, error) {
return nopWriterSyncCloser{r.stderr}, nil
})
// this error is expected if the sink is already registered.
duplicateSinkErr := fmt.Errorf("sink factory already registered for scheme %q", writerkey)
if err != nil && err.Error() != duplicateSinkErr.Error() {
r.Logger.Error("failed to register logger sink", zap.Error(err))
return
}
err = flag.Set("log.encoding", "json")
if err != nil {
r.Logger.Error("failed to set log encoding", zap.Error(err))
return
}
// create a new logger with the writer as the output path.
path := fmt.Sprintf("%s:subprocess", writerkey)
logger, err := process.NewLoggerWithOutputPaths("lazyfilewalker", path)
if err != nil {
r.Logger.Error("failed to create logger", zap.Error(err))
return
}
// set the logger to the new logger.
r.Logger = logger
}
type nopWriterSyncCloser struct {
io.Writer
}
func (cw nopWriterSyncCloser) Close() error { return nil }
func (cw nopWriterSyncCloser) Sync() error { return nil }