storj/cmd/storagenode/service_windows.go
Clement Sam 3cf89633e9 cmd/storagenode: refactor main.go
The cmd/storagenode/main.go is a big mess right now with so many
unneeded config structures initialized and shared by several
subcommands.

There are many instances where the config structure of one subcommand
is mistakenly used for another subcommand.

This changes is an attempt to clean up the main.go by moving the
subcommands to a separate `cmd_*.go` files with separate config structures
for each subcommand.

Resolves https://github.com/storj/storj/issues/5756

Change-Id: I85adf2439acba271c023c269739f7fa3c6d49f9d
2023-04-06 12:48:23 +00:00

98 lines
2.3 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
// Implements support for running the storage node as a Windows Service.
//
// The Windows Service can be created with sc.exe, e.g.
//
// sc.exe create storagenode binpath= "C:\Users\MyUser\storagenode.exe run --config-dir C:\Users\MyUser\"
//
// The --config-dir argument can be omitted if the config.yaml is available at
// C:\Windows\System32\config\systemprofile\AppData\Roaming\Storj\Storagenode\config.yaml
package main
import (
"os"
"github.com/spf13/cobra"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"golang.org/x/sys/windows/svc"
"storj.io/private/process"
)
var rootCmd, runCmd *cobra.Command
func startAsService() bool {
isService, err := svc.IsWindowsService()
if err != nil {
zap.L().Fatal("Failed to determine if session is a service.", zap.Error(err))
}
if !isService {
return false
}
// Check if the 'run' command is invoked
if len(os.Args) < 2 {
return false
}
if os.Args[1] != "run" {
return false
}
var factory *Factory
rootCmd, factory = newRootCmd(true)
runCmd = newRunCmd(factory)
// Initialize the Windows Service handler
err = svc.Run("storagenode", &service{})
if err != nil {
zap.L().Fatal("Service failed.", zap.Error(err))
}
return true
}
type service struct{}
func (m *service) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
changes <- svc.Status{State: svc.StartPending}
var group errgroup.Group
group.Go(func() error {
process.Exec(rootCmd)
return nil
})
defer func() { _ = group.Wait() }()
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
cmdloop:
for c := range r {
switch c.Cmd {
case svc.Interrogate:
zap.L().Info("Interrogate request received.")
changes <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
zap.L().Info("Stop/Shutdown request received.")
// Cancel the command's root context to cleanup resources
_, cancel := process.Ctx(runCmd)
cancel()
changes <- svc.Status{State: svc.StopPending, Accepts: cmdsAccepted}
break cmdloop
default:
zap.L().Info("Unexpected control request.", zap.Uint32("Event Type", c.EventType))
}
}
return false, 0
}