diff --git a/pkg/snclient/commands/daemon.go b/pkg/snclient/commands/daemon.go index a173fb5..dd723a0 100644 --- a/pkg/snclient/commands/daemon.go +++ b/pkg/snclient/commands/daemon.go @@ -14,7 +14,7 @@ func init() { All logs will be written to the configured logfile. `, GroupID: "daemon", - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, _ []string) { agentFlags.Mode = snclient.ModeServer snc := snclient.NewAgent(agentFlags) snc.CheckUpdateBinary("daemon") diff --git a/pkg/snclient/commands/dev.go b/pkg/snclient/commands/dev.go index dc2dc0e..c41fbc9 100644 --- a/pkg/snclient/commands/dev.go +++ b/pkg/snclient/commands/dev.go @@ -1,6 +1,9 @@ package commands import ( + "fmt" + "os" + "pkg/snclient" "github.com/spf13/cobra" @@ -10,9 +13,12 @@ func init() { devCmd := &cobra.Command{ Use: "dev", Short: "Collection of development commands", - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, _ []string) { rootCmd.SetArgs([]string{"help", "dev"}) - rootCmd.Execute() + if err := rootCmd.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "command failed: %s", err.Error()) + os.Exit(3) + } }, Hidden: true, } @@ -25,7 +31,7 @@ func init() { Long: `start the agent and watch for file changes in the config files or the agent itself. The agent will be restarted immediately on file changes. `, - Run: func(cmd *cobra.Command, _ []string) { + Run: func(_ *cobra.Command, _ []string) { agentFlags.Mode = snclient.ModeServer snc := snclient.NewAgent(agentFlags) snc.StartRestartWatcher() diff --git a/pkg/snclient/commands/hash.go b/pkg/snclient/commands/hash.go index 47a3902..eef8d40 100644 --- a/pkg/snclient/commands/hash.go +++ b/pkg/snclient/commands/hash.go @@ -29,7 +29,7 @@ snclient hash Run: func(cmd *cobra.Command, args []string) { agentFlags.Mode = snclient.ModeOneShot setInteractiveStdoutLogger() - input := "" + var input string if len(args) > 0 { input = args[0] } else { @@ -55,7 +55,7 @@ snclient hash func readPassword(cmd *cobra.Command) string { fmt.Fprintf(cmd.OutOrStdout(), "enter password to hash or hit ctrl+c to exit.\n") - b, _ := term.ReadPassword(int(syscall.Stdin)) + b, _ := term.ReadPassword(int(syscall.Stdin)) //nolint:unconvert,nolintlint // unconvert detects a conversion here but it is one on windows return string(b) } diff --git a/pkg/snclient/commands/install.go b/pkg/snclient/commands/install.go index 5e6a470..5d04c8d 100644 --- a/pkg/snclient/commands/install.go +++ b/pkg/snclient/commands/install.go @@ -50,48 +50,7 @@ It will also change some basic settings from the setup dialog. Ex. the initial p Use: "pkg [args]", Short: "called from the msi installer, set up firewall and service according to setup dialog", Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - snc := snclient.NewAgent(agentFlags) - - installConfig := parseInstallerArgs(args) - snc.Log.Infof("starting installer: %#v", installConfig) - - // merge tmp_installer.ini into snclient.ini - err := mergeIniFile(snc, installConfig) - if err != nil { - snc.Log.Errorf("failed to write install ini: %s", err.Error()) - } - - // reload config - snc.Init() - - if hasService(WINSERVICE) { - if serviceEnabled(WINSERVICE) { - err := restartService(WINSERVICE) - if err != nil { - snc.Log.Errorf("failed to (re)start service: %s", err.Error()) - } - } - } else { - err := installService(WINSERVICE) - if err != nil { - snc.Log.Errorf("failed to install service: %s", err.Error()) - } - - err = startService(WINSERVICE) - if err != nil { - snc.Log.Errorf("failed to start service: %s", err.Error()) - } - } - - err = addFireWallRule(snc) - if err != nil { - snc.Log.Errorf("failed to add firewall: %s", err.Error()) - } - snc.Log.Infof("installer finished successfully") - snc.CleanExit(0) - }, + Run: installPkg, }) // install pre @@ -99,43 +58,95 @@ It will also change some basic settings from the setup dialog. Ex. the initial p Use: "pre [args]", Short: "called from the msi installer, stop services", Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - snc := snclient.NewAgent(agentFlags) - - installConfig := parseInstallerArgs(args) - snc.Log.Infof("starting pre script: %#v", installConfig) - - if hasService(WINSERVICE) { - err := stopService(WINSERVICE) - if err != nil { - snc.Log.Infof("failed to stop service: %s", err.Error()) - } - } - snc.Log.Infof("pre script finished successfully") - snc.CleanExit(0) - }, + Run: installPre, }) // install firewall installCmd.AddCommand(&cobra.Command{ Use: "firewall [args]", Short: "add firewall exceptions for enabled tcp listeners, ex.: " + strings.Join(listenerNames, ", "), - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - setInteractiveStdoutLogger() - snc := snclient.NewAgent(agentFlags) - - err := addFireWallRule(snc) - if err != nil { - snc.Log.Errorf("failed to add firewall: %s", err.Error()) - } - snc.Log.Infof("firewall setup ready") - snc.CleanExit(0) - }, + Run: installFirewall, }) } +func installPkg(_ *cobra.Command, args []string) { + agentFlags.Mode = snclient.ModeOneShot + snc := snclient.NewAgent(agentFlags) + + installConfig := parseInstallerArgs(args) + snc.Log.Infof("starting installer: %#v", installConfig) + + // merge tmp_installer.ini into snclient.ini + err := mergeIniFile(snc, installConfig) + if err != nil { + snc.Log.Errorf("failed to write install ini: %s", err.Error()) + } + + // reload config + _, err = snc.Init() + if err != nil { + snc.Log.Errorf("failed to reload config: %s", err.Error()) + } + + switch hasService(WINSERVICE) { + case false: + err = installService(WINSERVICE) + if err != nil { + snc.Log.Errorf("failed to install service: %s", err.Error()) + } + + err = startService(WINSERVICE) + if err != nil { + snc.Log.Errorf("failed to start service: %s", err.Error()) + } + case true: + if !serviceEnabled(WINSERVICE) { + break + } + err = restartService(WINSERVICE) + if err != nil { + snc.Log.Errorf("failed to (re)start service: %s", err.Error()) + } + } + + err = addFireWallRule(snc) + if err != nil { + snc.Log.Errorf("failed to add firewall: %s", err.Error()) + } + snc.Log.Infof("installer finished successfully") + snc.CleanExit(0) +} + +func installPre(_ *cobra.Command, args []string) { + agentFlags.Mode = snclient.ModeOneShot + snc := snclient.NewAgent(agentFlags) + + installConfig := parseInstallerArgs(args) + snc.Log.Infof("starting pre script: %#v", installConfig) + + if hasService(WINSERVICE) { + err := stopService(WINSERVICE) + if err != nil { + snc.Log.Infof("failed to stop service: %s", err.Error()) + } + } + snc.Log.Infof("pre script finished successfully") + snc.CleanExit(0) +} + +func installFirewall(_ *cobra.Command, _ []string) { + agentFlags.Mode = snclient.ModeOneShot + setInteractiveStdoutLogger() + snc := snclient.NewAgent(agentFlags) + + err := addFireWallRule(snc) + if err != nil { + snc.Log.Errorf("failed to add firewall: %s", err.Error()) + } + snc.Log.Infof("firewall setup ready") + snc.CleanExit(0) +} + func parseInstallerArgs(args []string) (parsed map[string]string) { parsed = make(map[string]string, 0) if len(args) == 0 { @@ -157,16 +168,21 @@ func removeService(name string) error { } svcMgr, err := mgr.Connect() if err != nil { - return err + return fmt.Errorf("mgr.Connect: %s", err.Error()) } - defer svcMgr.Disconnect() + defer func() { _ = svcMgr.Disconnect() }() service, err := svcMgr.OpenService(name) if err != nil { - return err + return fmt.Errorf("svcMgr.OpenService: %s", err.Error()) + } + + err = windows.DeleteService(service.Handle) + if err != nil { + return fmt.Errorf("windows.DeleteService: %s", err.Error()) } - return windows.DeleteService(service.Handle) + return nil } func hasService(name string) bool { @@ -174,7 +190,7 @@ func hasService(name string) bool { if err != nil { return false } - defer svcMgr.Disconnect() + defer func() { _ = svcMgr.Disconnect() }() service, err := svcMgr.OpenService(name) if err != nil { @@ -190,7 +206,7 @@ func serviceEnabled(name string) bool { if err != nil { return false } - defer svcMgr.Disconnect() + defer func() { _ = svcMgr.Disconnect() }() service, err := svcMgr.OpenService(name) if err != nil { @@ -209,21 +225,24 @@ func serviceEnabled(name string) bool { func stopService(name string) error { svcMgr, err := mgr.Connect() if err != nil { - return err + return fmt.Errorf("mgr.Connect: %s", err.Error()) } - defer svcMgr.Disconnect() + defer func() { _ = svcMgr.Disconnect() }() service, err := svcMgr.OpenService(name) if err != nil { - return err + return fmt.Errorf("svcMgr.OpenService: %s", err.Error()) } defer service.Close() state, err := service.Query() + if err != nil { + return fmt.Errorf("service.Query: %s", err.Error()) + } if state.State != svc.Stopped { state, err = service.Control(svc.Stop) if err != nil { - return err + return fmt.Errorf("service.Control: %s", err.Error()) } } @@ -237,7 +256,7 @@ func stopService(name string) error { time.Sleep(WINSERVICESTOPINTERVALL) state, err = service.Query() if err != nil { - return err + return fmt.Errorf("service.Query: %s", err.Error()) } if time.Now().After(startWait.Add(WINSERVICESTOPTIMEOUT)) { return fmt.Errorf("could not stop service within %s, current state: %v", WINSERVICESTOPTIMEOUT, state) @@ -250,19 +269,19 @@ func stopService(name string) error { func startService(name string) error { svcMgr, err := mgr.Connect() if err != nil { - return err + return fmt.Errorf("mgr.Connect: %s", err.Error()) } - defer svcMgr.Disconnect() + defer func() { _ = svcMgr.Disconnect() }() service, err := svcMgr.OpenService(name) if err != nil { - return err + return fmt.Errorf("svcMgr.OpenService: %s", err.Error()) } defer service.Close() err = service.Start() if err != nil { - return err + return fmt.Errorf("service.Start: %s", err.Error()) } return nil @@ -273,6 +292,7 @@ func restartService(name string) error { if err != nil { return err } + return startService(name) } @@ -282,11 +302,14 @@ func installService(name string) error { } svcMgr, err := mgr.Connect() if err != nil { - return err + return fmt.Errorf("mgr.Connect: %s", err.Error()) } - defer svcMgr.Disconnect() + defer func() { _ = svcMgr.Disconnect() }() _, _, execPath, err := utils.GetExecutablePath() + if err != nil { + return fmt.Errorf("utils.GetExecutablePath: %s", err.Error()) + } _, err = svcMgr.CreateService( name, execPath, @@ -301,6 +324,7 @@ func installService(name string) error { if err != nil { return fmt.Errorf("windows.CreateService: %s", err.Error()) } + return nil } @@ -333,7 +357,7 @@ func mergeIniFile(snc *snclient.Agent, installConfig map[string]string) error { if err != nil { snc.Log.Errorf("failed to read %s: %s", targetFile, err.Error()) - return err + return fmt.Errorf("open %s: %s", targetFile, err.Error()) } defer file.Close() err = targetConfig.ParseINI(file, targetFile, snc) @@ -415,7 +439,7 @@ func addFireWallRule(snc *snclient.Agent) error { if err != nil { return fmt.Errorf("could not detect path to executable: %s", err.Error()) } - os.Chdir("C:\\") // avoid: exec: "netsh": cannot run executable found relative to current directory + _ = os.Chdir("C:\\") // avoid: exec: "netsh": cannot run executable found relative to current directory cmdLine := []string{ "advfirewall", "firewall", "add", "rule", "dir=in", @@ -433,7 +457,7 @@ func addFireWallRule(snc *snclient.Agent) error { output, err := cmd.CombinedOutput() output = bytes.TrimSpace(output) if err != nil { - return fmt.Errorf("Failed to create firewall exception: %s (%s)", err.Error(), output) + return fmt.Errorf("failed to create firewall exception: %s (%s)", err.Error(), output) } snc.Log.Debugf("added firewall: %s", output) @@ -459,7 +483,7 @@ func removeFireWallRules(snc *snclient.Agent) { func removeFireWallRule(snc *snclient.Agent, name string) error { snc.Log.Debugf("removing firewall rule '%s%s'", FIREWALLPREFIX, name) - os.Chdir("C:\\") // avoid: exec: "netsh": cannot run executable found relative to current directory + _ = os.Chdir("C:\\") // avoid: exec: "netsh": cannot run executable found relative to current directory cmdLine := []string{ "advfirewall", "firewall", "delete", "rule", @@ -472,7 +496,7 @@ func removeFireWallRule(snc *snclient.Agent, name string) error { output, err := cmd.CombinedOutput() output = bytes.TrimSpace(output) if err != nil { - return fmt.Errorf("Failed to remove firewall exception: %s (%s)", err.Error(), output) + return fmt.Errorf("failed to remove firewall exception: %s (%s)", err.Error(), output) } snc.Log.Debugf("removed firewall: %s", output) diff --git a/pkg/snclient/commands/inventory.go b/pkg/snclient/commands/inventory.go index c6e9865..8ca42bc 100644 --- a/pkg/snclient/commands/inventory.go +++ b/pkg/snclient/commands/inventory.go @@ -23,7 +23,7 @@ snclient inventory # print inventory for mounts only snclient inventory mounts `, - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, args []string) { agentFlags.Mode = snclient.ModeOneShot setInteractiveStdoutLogger() snc := snclient.NewAgent(agentFlags) diff --git a/pkg/snclient/commands/root.go b/pkg/snclient/commands/root.go index 360188b..1fd3e3b 100644 --- a/pkg/snclient/commands/root.go +++ b/pkg/snclient/commands/root.go @@ -31,11 +31,12 @@ while being easily extendible with own script and checks.`, * Check for update in verbose mode %> snclient update -v `, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, _ []string) error { // defaults to server mode unless --help/--version is given if agentFlags.Version { snc := snclient.Agent{} snc.PrintVersion() + return nil } @@ -44,7 +45,7 @@ while being easily extendible with own script and checks.`, } // should never reach this point - return fmt.Errorf("snclient called without arguments, see --help for usage.") + return fmt.Errorf("snclient called without arguments, see --help for usage") }, } @@ -68,7 +69,10 @@ func addFlags(cmd *cobra.Command, flags *snclient.AgentFlags) { cmd.PersistentFlags().StringVarP(&flags.ProfileCPU, "cpuprofile", "", "", "write cpu profile to `file") cmd.PersistentFlags().StringVarP(&flags.ProfileMem, "memprofile", "", "", "write memory profile to `file") cmd.PersistentFlags().IntVarP(&flags.DeadlockTimeout, "debug-deadlock", "", 0, "enable deadlock detection with given timeout") - cmd.PersistentFlags().MarkHidden("debug-deadlock") // there are no lock so far + // there are no locks so far + if err := cmd.PersistentFlags().MarkHidden("debug-deadlock"); err != nil { + panic("markhidden failed") + } cmd.DisableAutoGenTag = true cmd.DisableSuggestions = true @@ -84,7 +88,13 @@ func Execute() error { injectDoubleSlashAfterRunCmd(rootCmd) sanitizeOSArgs() maybeInjectRootAlias(rootCmd, "server") - return rootCmd.Execute() + + err := rootCmd.Execute() + if err != nil { + return fmt.Errorf("cmd failed: %s", err.Error()) + } + + return nil } // inject given command unless there is one already @@ -105,13 +115,18 @@ func maybeInjectRootAlias(rootCmd *cobra.Command, inject string) { // parse flags (ignoring unknown flags for subcommands) and check if we want help or version only tmpCmd.FParseErrWhitelist.UnknownFlags = true - tmpCmd.ParseFlags(args) + err = tmpCmd.ParseFlags(args) + if err != nil { + return + } if tmpFlags.Version { os.Args = []string{os.Args[0], "-V"} + return } if tmpFlags.Help { os.Args = []string{os.Args[0], "-h"} + return } @@ -134,16 +149,16 @@ func sanitizeOSArgs() { } }) } - for i, a := range os.Args { - if i == 0 { + for idx, arg := range os.Args { + if idx == 0 { continue } - if r, ok := replace[a]; ok { - os.Args[i] = r + if r, ok := replace[arg]; ok { + os.Args[idx] = r } for n, r := range replace { - if strings.HasPrefix(a, n+"=") { - os.Args[i] = r + "=" + strings.TrimPrefix(os.Args[i], n+"=") + if strings.HasPrefix(arg, n+"=") { + os.Args[idx] = r + "=" + strings.TrimPrefix(os.Args[idx], n+"=") } } } @@ -170,17 +185,19 @@ func injectDoubleSlashAfterRunCmd(rootCmd *cobra.Command) { // search start of cmd args found := 0 - for i, a := range os.Args { - if strings.HasPrefix(a, "-") { + for idx, arg := range os.Args { + if strings.HasPrefix(arg, "-") { continue } - if a == cmd.Name() { - found = i + if arg == cmd.Name() { + found = idx + break } for _, n := range cmd.Aliases { - if a == n { - found = i + if arg == n { + found = idx + break } } @@ -198,6 +215,7 @@ func injectDoubleSlashAfterRunCmd(rootCmd *cobra.Command) { for i, a := range os.Args[found+1:] { if !strings.HasPrefix(a, "-") { found2 = i + break } } diff --git a/pkg/snclient/commands/root_test.go b/pkg/snclient/commands/root_test.go index ccf1d17..ae29e33 100644 --- a/pkg/snclient/commands/root_test.go +++ b/pkg/snclient/commands/root_test.go @@ -37,13 +37,16 @@ func RunCommand(t *testing.T, cmd *cobra.Command, args []string) (output string, }() cmd.Flags().VisitAll(func(f *pflag.Flag) { - f.Value.Set(f.DefValue) + err = f.Value.Set(f.DefValue) + require.NoError(t, err) }) cmd.SetArgs(args) err = cmd.Execute() + require.NoError(t, err) outFile.Close() outputBytes, err := os.ReadFile(outFile.Name()) + return string(outputBytes), err } diff --git a/pkg/snclient/commands/server.go b/pkg/snclient/commands/server.go index 49042bd..e9cdcaa 100644 --- a/pkg/snclient/commands/server.go +++ b/pkg/snclient/commands/server.go @@ -14,7 +14,7 @@ func init() { All logs will be printed to stdout unless flags tell otherwise. `, GroupID: "daemon", - Run: func(cmd *cobra.Command, _ []string) { + Run: func(_ *cobra.Command, _ []string) { agentFlags.Mode = snclient.ModeServer snc := snclient.NewAgent(agentFlags) snc.CheckUpdateBinary("server") diff --git a/pkg/snclient/commands/test.go b/pkg/snclient/commands/test.go index ed2334a..96a931b 100644 --- a/pkg/snclient/commands/test.go +++ b/pkg/snclient/commands/test.go @@ -54,7 +54,7 @@ snclient do check_files path=/tmp crit='count > 100' if len(args) == 0 { if cmd.CalledAs() != "test" { - cmd.Usage() + _ = cmd.Usage() snc.CleanExit(snclient.ExitCodeUnknown) } @@ -78,6 +78,7 @@ func testPrompt(cmd *cobra.Command, snc *snclient.Agent) { checks = append(checks, chk) } } + return readline.CompleteValues(checks...) } @@ -86,7 +87,7 @@ func testPrompt(cmd *cobra.Command, snc *snclient.Agent) { rl := readline.NewShell() rl.Prompt.Primary(func() string { return ">> " }) - rl.Config.Set("show-mode-in-prompt", false) + _ = rl.Config.Set("show-mode-in-prompt", false) rl.Completer = promptCompleter for { text, err := rl.Readline() @@ -128,7 +129,7 @@ func testHelp(cmd *cobra.Command) { fmt.Fprintf(rootCmd.OutOrStdout(), "%s", cmd.Long) } -func testPrintHuman(cmd *cobra.Command, res *snclient.CheckResult) { +func testPrintHuman(_ *cobra.Command, res *snclient.CheckResult) { fmt.Fprintf(rootCmd.OutOrStdout(), "Exit Code: %s (%d)\n", res.StateString(), res.State) fmt.Fprintf(rootCmd.OutOrStdout(), "Plugin Output:\n") fmt.Fprintf(rootCmd.OutOrStdout(), "%s\n", res.Output) @@ -140,7 +141,7 @@ func testPrintHuman(cmd *cobra.Command, res *snclient.CheckResult) { } } -func testPrintNaemon(cmd *cobra.Command, res *snclient.CheckResult) { +func testPrintNaemon(_ *cobra.Command, res *snclient.CheckResult) { output := string(res.BuildPluginOutput()) output = strings.TrimSpace(output) fmt.Fprintf(rootCmd.OutOrStdout(), "%s\n", output) diff --git a/pkg/snclient/commands/uninstall.go b/pkg/snclient/commands/uninstall.go index f31143f..85b2a7a 100644 --- a/pkg/snclient/commands/uninstall.go +++ b/pkg/snclient/commands/uninstall.go @@ -24,26 +24,7 @@ func init() { uninstallCmd.AddCommand(&cobra.Command{ Use: "stop [args]", Short: "called from the msi installer stop the service", - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - snc := snclient.NewAgent(agentFlags) - - snc.Log.Infof("uninstaller: stop") - if hasService(WINSERVICE) { - err := stopService(WINSERVICE) - if err != nil { - snc.Log.Errorf("failed to stops service: %s", err.Error()) - } - } - snc.Log.Infof("stop completed") - - err := removeService(WINSERVICE) - if err != nil { - snc.Log.Errorf("failed to remove service: %s", err.Error()) - } - - snc.CleanExit(0) - }, + Run: uninstallStop, }) // uninstall pkg @@ -51,53 +32,7 @@ func init() { Use: "pkg [args]", Short: "called from the msi installer, removes firewall and service if agent gets uninstalled", Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - snc := snclient.NewAgent(agentFlags) - - installConfig := parseInstallerArgs(args) - if installConfig["REMOVE"] != "ALL" || installConfig["UPGRADINGPRODUCTCODE"] != "" { - snc.Log.Infof("skipping uninstall: %#v", installConfig) - snc.CleanExit(0) - } - - snc.Log.Infof("starting uninstaller: %#v", installConfig) - if hasService(WINSERVICE) { - err := stopService("snclient") - if err != nil { - snc.Log.Errorf("failed to stops service: %s", err.Error()) - } - err = removeService("snclient") - if err != nil { - snc.Log.Errorf("failed to remove service: %s", err.Error()) - } - } - - // cleanup windows_exporter textfile_inputs folder - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "exporter", "textfile_inputs")) - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "exporter")) - - removeFireWallRules(snc) - - snc.Log.Infof("uninstall completed") - - // close log file so we can delete it - snc.Log.SetOutput(os.Stderr) - if snclient.LogFileHandle != nil { - snclient.LogFileHandle.Close() - snclient.LogFileHandle = nil - } - - // since files are installed with Permanent=yes, we need to remove them manually now - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "cacert.pem")) - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "server.crt")) - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "server.key")) - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "snclient.ini")) - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "snclient.log")) - _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "snclient.log.old")) - - snc.CleanExit(0) - }, + Run: uninstallPkg, }) // uninstall firewall @@ -105,14 +40,85 @@ func init() { Use: "firewall [args]", Short: "remove existing firewall rules", Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - snc := snclient.NewAgent(agentFlags) + Run: uninstallFirewall, + }) +} - removeFireWallRules(snc) +func uninstallStop(_ *cobra.Command, _ []string) { + agentFlags.Mode = snclient.ModeOneShot + snc := snclient.NewAgent(agentFlags) - snc.Log.Infof("firewall exceptions removed") - snc.CleanExit(0) - }, - }) + snc.Log.Infof("uninstaller: stop") + if hasService(WINSERVICE) { + err := stopService(WINSERVICE) + if err != nil { + snc.Log.Errorf("failed to stops service: %s", err.Error()) + } + } + snc.Log.Infof("stop completed") + + err := removeService(WINSERVICE) + if err != nil { + snc.Log.Errorf("failed to remove service: %s", err.Error()) + } + + snc.CleanExit(0) +} + +func uninstallPkg(_ *cobra.Command, args []string) { + agentFlags.Mode = snclient.ModeOneShot + snc := snclient.NewAgent(agentFlags) + + installConfig := parseInstallerArgs(args) + if installConfig["REMOVE"] != "ALL" || installConfig["UPGRADINGPRODUCTCODE"] != "" { + snc.Log.Infof("skipping uninstall: %#v", installConfig) + snc.CleanExit(0) + } + + snc.Log.Infof("starting uninstaller: %#v", installConfig) + if hasService(WINSERVICE) { + err := stopService("snclient") + if err != nil { + snc.Log.Errorf("failed to stops service: %s", err.Error()) + } + err = removeService("snclient") + if err != nil { + snc.Log.Errorf("failed to remove service: %s", err.Error()) + } + } + + // cleanup windows_exporter textfile_inputs folder + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "exporter", "textfile_inputs")) + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "exporter")) + + removeFireWallRules(snc) + + snc.Log.Infof("uninstall completed") + + // close log file so we can delete it + snc.Log.SetOutput(os.Stderr) + if snclient.LogFileHandle != nil { + snclient.LogFileHandle.Close() + snclient.LogFileHandle = nil + } + + // since files are installed with Permanent=yes, we need to remove them manually now + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "cacert.pem")) + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "server.crt")) + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "server.key")) + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "snclient.ini")) + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "snclient.log")) + _ = os.Remove(filepath.Join(installConfig["INSTALLDIR"], "snclient.log.old")) + + snc.CleanExit(0) +} + +func uninstallFirewall(_ *cobra.Command, _ []string) { + agentFlags.Mode = snclient.ModeOneShot + snc := snclient.NewAgent(agentFlags) + + removeFireWallRules(snc) + + snc.Log.Infof("firewall exceptions removed") + snc.CleanExit(0) } diff --git a/pkg/snclient/commands/update.go b/pkg/snclient/commands/update.go index f2f93d1..6add741 100644 --- a/pkg/snclient/commands/update.go +++ b/pkg/snclient/commands/update.go @@ -3,11 +3,12 @@ package commands import ( "fmt" "os" - "pkg/convert" - "pkg/snclient" "strings" "time" + "pkg/convert" + "pkg/snclient" + "github.com/spf13/cobra" "golang.org/x/exp/slices" ) @@ -34,54 +35,7 @@ snclient update --prerelease --check all # apply downgrade to version 0.19: snclient update --downgrade=0.19 `, - Run: func(cmd *cobra.Command, args []string) { - agentFlags.Mode = snclient.ModeOneShot - setInteractiveStdoutLogger() - snc := snclient.NewAgent(agentFlags) - executable := snclient.GlobalMacros["exe-full"] - if strings.Contains(executable, ".update") || slices.Contains(args, "apply") { - time.Sleep(500 * time.Millisecond) - snc.CheckUpdateBinary("update") - snc.CleanExit(0) - } - task := snc.Tasks.Get("Updates") - switch mod := task.(type) { - case *snclient.UpdateHandler: - channel := "" - if len(args) > 0 { - channel = channel + "," + strings.Join(args, ",") - } else { - channel = cmd.Flag("channel").Value.String() - } - channel = strings.TrimPrefix(channel, ",") - checkOnly := convert.Bool(cmd.Flag("check").Value.String()) - preRelease := convert.Bool(cmd.Flag("prerelease").Value.String()) - force := convert.Bool(cmd.Flag("force").Value.String()) - version, err := mod.CheckUpdates( - true, - !checkOnly, - false, - preRelease, - cmd.Flag("downgrade").Value.String(), - channel, - force, - ) - if err != nil { - fmt.Fprintf(os.Stderr, "update check failed: %s\n", err.Error()) - snc.CleanExit(3) - } - if version == "" { - fmt.Fprintf(os.Stdout, "no new updates available (current version: %s - build: %s)\n", snc.Version(), snclient.Build) - snc.CleanExit(0) - } - if checkOnly { - fmt.Fprintf(os.Stdout, "new update available to version: %s\n", version) - snc.CleanExit(1) - } - fmt.Fprintf(os.Stdout, "update to version %s applied successfully\n", version) - snc.CleanExit(0) - } - }, + Run: runUpdates, } updateCmd.PersistentFlags().String("channel", "", "Select download channel.") @@ -91,3 +45,57 @@ snclient update --downgrade=0.19 updateCmd.PersistentFlags().BoolP("force", "f", false, "Force update.") rootCmd.AddCommand(updateCmd) } + +func runUpdates(cmd *cobra.Command, args []string) { + agentFlags.Mode = snclient.ModeOneShot + setInteractiveStdoutLogger() + snc := snclient.NewAgent(agentFlags) + executable := snclient.GlobalMacros["exe-full"] + if strings.Contains(executable, ".update") || slices.Contains(args, "apply") { + time.Sleep(500 * time.Millisecond) + snc.CheckUpdateBinary("update") + snc.CleanExit(0) + } + task := snc.Tasks.Get("Updates") + mod, ok := task.(*snclient.UpdateHandler) + if !ok { + fmt.Fprintf(os.Stderr, "could not load update handler") + snc.CleanExit(3) + + return + } + + channel := "" + if len(args) > 0 { + channel = channel + "," + strings.Join(args, ",") + } else { + channel = cmd.Flag("channel").Value.String() + } + channel = strings.TrimPrefix(channel, ",") + checkOnly := convert.Bool(cmd.Flag("check").Value.String()) + preRelease := convert.Bool(cmd.Flag("prerelease").Value.String()) + force := convert.Bool(cmd.Flag("force").Value.String()) + version, err := mod.CheckUpdates( + true, + !checkOnly, + false, + preRelease, + cmd.Flag("downgrade").Value.String(), + channel, + force, + ) + if err != nil { + fmt.Fprintf(os.Stderr, "update check failed: %s\n", err.Error()) + snc.CleanExit(3) + } + if version == "" { + fmt.Fprintf(os.Stdout, "no new updates available (current version: %s - build: %s)\n", snc.Version(), snclient.Build) + snc.CleanExit(0) + } + if checkOnly { + fmt.Fprintf(os.Stdout, "new update available to version: %s\n", version) + snc.CleanExit(1) + } + fmt.Fprintf(os.Stdout, "update to version %s applied successfully\n", version) + snc.CleanExit(0) +} diff --git a/pkg/snclient/commands/winservice.go b/pkg/snclient/commands/winservice.go index 97e0ac8..bfd9b46 100644 --- a/pkg/snclient/commands/winservice.go +++ b/pkg/snclient/commands/winservice.go @@ -18,7 +18,7 @@ func init() { All logs will be written to the configured logfile. `, GroupID: "daemon", - Run: func(cmd *cobra.Command, _ []string) { + Run: func(_ *cobra.Command, _ []string) { agentFlags.Mode = snclient.ModeServer snc := snclient.NewAgent(agentFlags) snc.CheckUpdateBinary("winservice")