TUN-5881: Clarify success (or lack thereof) of (un)installing cloudflared service

This commit is contained in:
Nuno Diegues 2022-03-18 09:42:45 +00:00
parent 05b903a32e
commit 1b511b2d25
3 changed files with 64 additions and 44 deletions

View File

@ -19,16 +19,16 @@ import (
func runApp(app *cli.App, graceShutdownC chan struct{}) { func runApp(app *cli.App, graceShutdownC chan struct{}) {
app.Commands = append(app.Commands, &cli.Command{ app.Commands = append(app.Commands, &cli.Command{
Name: "service", Name: "service",
Usage: "Manages the Cloudflare Tunnel system service", Usage: "Manages the cloudflared system service",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "install", Name: "install",
Usage: "Install Cloudflare Tunnel as a system service", Usage: "Install cloudflared as a system service",
Action: cliutil.ConfiguredAction(installLinuxService), Action: cliutil.ConfiguredAction(installLinuxService),
}, },
{ {
Name: "uninstall", Name: "uninstall",
Usage: "Uninstall the Cloudflare Tunnel service", Usage: "Uninstall the cloudflared service",
Action: cliutil.ConfiguredAction(uninstallLinuxService), Action: cliutil.ConfiguredAction(uninstallLinuxService),
}, },
}, },
@ -49,7 +49,7 @@ var systemdTemplates = []ServiceTemplate{
{ {
Path: "/etc/systemd/system/cloudflared.service", Path: "/etc/systemd/system/cloudflared.service",
Content: `[Unit] Content: `[Unit]
Description=Cloudflare Tunnel Description=cloudflared
After=network.target After=network.target
[Service] [Service]
@ -66,7 +66,7 @@ WantedBy=multi-user.target
{ {
Path: "/etc/systemd/system/cloudflared-update.service", Path: "/etc/systemd/system/cloudflared-update.service",
Content: `[Unit] Content: `[Unit]
Description=Update Cloudflare Tunnel Description=Update cloudflared
After=network.target After=network.target
[Service] [Service]
@ -76,7 +76,7 @@ ExecStart=/bin/bash -c '{{ .Path }} update; code=$?; if [ $code -eq 11 ]; then s
{ {
Path: "/etc/systemd/system/cloudflared-update.timer", Path: "/etc/systemd/system/cloudflared-update.timer",
Content: `[Unit] Content: `[Unit]
Description=Update Cloudflare Tunnel Description=Update cloudflared
[Timer] [Timer]
OnCalendar=daily OnCalendar=daily
@ -93,7 +93,7 @@ var sysvTemplate = ServiceTemplate{
Content: `#!/bin/sh Content: `#!/bin/sh
# For RedHat and cousins: # For RedHat and cousins:
# chkconfig: 2345 99 01 # chkconfig: 2345 99 01
# description: Cloudflare Tunnel agent # description: cloudflared
# processname: {{.Path}} # processname: {{.Path}}
### BEGIN INIT INFO ### BEGIN INIT INFO
# Provides: {{.Path}} # Provides: {{.Path}}
@ -101,8 +101,8 @@ var sysvTemplate = ServiceTemplate{
# Required-Stop: # Required-Stop:
# Default-Start: 2 3 4 5 # Default-Start: 2 3 4 5
# Default-Stop: 0 1 6 # Default-Stop: 0 1 6
# Short-Description: Cloudflare Tunnel # Short-Description: cloudflared
# Description: Cloudflare Tunnel agent # Description: cloudflared agent
### END INIT INFO ### END INIT INFO
name=$(basename $(readlink -f $0)) name=$(basename $(readlink -f $0))
cmd="{{.Path}} --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s{{ range .ExtraArgs }} {{ . }}{{ end }}" cmd="{{.Path}} --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s{{ range .ExtraArgs }} {{ . }}{{ end }}"
@ -212,11 +212,16 @@ func installLinuxService(c *cli.Context) error {
switch { switch {
case isSystemd(): case isSystemd():
log.Info().Msgf("Using Systemd") log.Info().Msgf("Using Systemd")
return installSystemd(&templateArgs, log) err = installSystemd(&templateArgs, log)
default: default:
log.Info().Msgf("Using SysV") log.Info().Msgf("Using SysV")
return installSysv(&templateArgs, log) err = installSysv(&templateArgs, log)
} }
if err == nil {
log.Info().Msg("Linux service for cloudflared installed successfully")
}
return err
} }
func buildArgsForConfig(c *cli.Context, log *zerolog.Logger) ([]string, error) { func buildArgsForConfig(c *cli.Context, log *zerolog.Logger) ([]string, error) {
@ -271,7 +276,7 @@ func installSystemd(templateArgs *ServiceTemplateArgs, log *zerolog.Logger) erro
log.Err(err).Msg("systemctl start cloudflared-update.timer error") log.Err(err).Msg("systemctl start cloudflared-update.timer error")
return err return err
} }
log.Info().Msg("systemctl daemon-reload") log.Info().Msg("running systemctl daemon-reload")
return runCommand("systemctl", "daemon-reload") return runCommand("systemctl", "daemon-reload")
} }
@ -301,14 +306,20 @@ func installSysv(templateArgs *ServiceTemplateArgs, log *zerolog.Logger) error {
func uninstallLinuxService(c *cli.Context) error { func uninstallLinuxService(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog) log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
var err error
switch { switch {
case isSystemd(): case isSystemd():
log.Info().Msg("Using Systemd") log.Info().Msg("Using Systemd")
return uninstallSystemd(log) err = uninstallSystemd(log)
default: default:
log.Info().Msg("Using SysV") log.Info().Msg("Using SysV")
return uninstallSysv(log) err = uninstallSysv(log)
} }
if err == nil {
log.Info().Msg("Linux service for cloudflared uninstalled successfully")
}
return err
} }
func uninstallSystemd(log *zerolog.Logger) error { func uninstallSystemd(log *zerolog.Logger) error {
@ -326,7 +337,6 @@ func uninstallSystemd(log *zerolog.Logger) error {
return err return err
} }
} }
log.Info().Msgf("Successfully uninstalled cloudflared service from systemd")
return nil return nil
} }
@ -345,6 +355,5 @@ func uninstallSysv(log *zerolog.Logger) error {
continue continue
} }
} }
log.Info().Msgf("Successfully uninstalled cloudflared service from sysv")
return nil return nil
} }

View File

@ -21,16 +21,16 @@ const (
func runApp(app *cli.App, graceShutdownC chan struct{}) { func runApp(app *cli.App, graceShutdownC chan struct{}) {
app.Commands = append(app.Commands, &cli.Command{ app.Commands = append(app.Commands, &cli.Command{
Name: "service", Name: "service",
Usage: "Manages the Cloudflare Tunnel launch agent", Usage: "Manages the cloudflared launch agent",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "install", Name: "install",
Usage: "Install Cloudflare Tunnel as an user launch agent", Usage: "Install cloudflared as an user launch agent",
Action: cliutil.ConfiguredAction(installLaunchd), Action: cliutil.ConfiguredAction(installLaunchd),
}, },
{ {
Name: "uninstall", Name: "uninstall",
Usage: "Uninstall the Cloudflare Tunnel launch agent", Usage: "Uninstall the cloudflared launch agent",
Action: cliutil.ConfiguredAction(uninstallLaunchd), Action: cliutil.ConfiguredAction(uninstallLaunchd),
}, },
}, },
@ -114,12 +114,12 @@ func installLaunchd(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog) log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
if isRootUser() { if isRootUser() {
log.Info().Msg("Installing Cloudflare Tunnel client as a system launch daemon. " + log.Info().Msg("Installing cloudflared client as a system launch daemon. " +
"Cloudflare Tunnel client will run at boot") "cloudflared client will run at boot")
} else { } else {
log.Info().Msg("Installing Cloudflare Tunnel client as an user launch agent. " + log.Info().Msg("Installing cloudflared client as an user launch agent. " +
"Note that Cloudflare Tunnel client will only run when the user is logged in. " + "Note that cloudflared client will only run when the user is logged in. " +
"If you want to run Cloudflare Tunnel client at boot, install with root permission. " + "If you want to run cloudflared client at boot, install with root permission. " +
"For more information, visit https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/run-as-service") "For more information, visit https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/run-as-service")
} }
etPath, err := os.Executable() etPath, err := os.Executable()
@ -163,16 +163,20 @@ func installLaunchd(c *cli.Context) error {
} }
log.Info().Msgf("Outputs are logged to %s and %s", stderrPath, stdoutPath) log.Info().Msgf("Outputs are logged to %s and %s", stderrPath, stdoutPath)
return runCommand("launchctl", "load", plistPath) err = runCommand("launchctl", "load", plistPath)
if err == nil {
log.Info().Msg("MacOS service for cloudflared installed successfully")
}
return err
} }
func uninstallLaunchd(c *cli.Context) error { func uninstallLaunchd(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog) log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
if isRootUser() { if isRootUser() {
log.Info().Msg("Uninstalling Cloudflare Tunnel as a system launch daemon") log.Info().Msg("Uninstalling cloudflared as a system launch daemon")
} else { } else {
log.Info().Msg("Uninstalling Cloudflare Tunnel as an user launch agent") log.Info().Msg("Uninstalling cloudflared as a user launch agent")
} }
installPath, err := installPath() installPath, err := installPath()
if err != nil { if err != nil {
@ -194,10 +198,13 @@ func uninstallLaunchd(c *cli.Context) error {
} }
err = runCommand("launchctl", "unload", plistPath) err = runCommand("launchctl", "unload", plistPath)
if err != nil { if err != nil {
log.Err(err).Msg("error unloading") log.Err(err).Msg("error unloading launchd")
return err return err
} }
log.Info().Msgf("Outputs are logged to %s and %s", stderrPath, stdoutPath) err = launchdTemplate.Remove()
return launchdTemplate.Remove() if err == nil {
log.Info().Msg("Launchd for cloudflared was uninstalled successfully")
}
return err
} }

View File

@ -26,8 +26,8 @@ import (
const ( const (
windowsServiceName = "Cloudflared" windowsServiceName = "Cloudflared"
windowsServiceDescription = "Cloudflare Tunnel agent" windowsServiceDescription = "Cloudflared agent"
windowsServiceUrl = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/run-as-service#windows" windowsServiceUrl = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/as-a-service/windows/"
recoverActionDelay = time.Second * 20 recoverActionDelay = time.Second * 20
failureCountResetPeriod = time.Hour * 24 failureCountResetPeriod = time.Hour * 24
@ -46,16 +46,16 @@ const (
func runApp(app *cli.App, graceShutdownC chan struct{}) { func runApp(app *cli.App, graceShutdownC chan struct{}) {
app.Commands = append(app.Commands, &cli.Command{ app.Commands = append(app.Commands, &cli.Command{
Name: "service", Name: "service",
Usage: "Manages the Cloudflare Tunnel Windows service", Usage: "Manages the cloudflared Windows service",
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "install", Name: "install",
Usage: "Install Cloudflare Tunnel as a Windows service", Usage: "Install cloudflared as a Windows service",
Action: cliutil.ConfiguredAction(installWindowsService), Action: cliutil.ConfiguredAction(installWindowsService),
}, },
{ {
Name: "uninstall", Name: "uninstall",
Usage: "Uninstall the Cloudflare Tunnel service", Usage: "Uninstall the cloudflared service",
Action: cliutil.ConfiguredAction(uninstallWindowsService), Action: cliutil.ConfiguredAction(uninstallWindowsService),
}, },
}, },
@ -177,7 +177,7 @@ func (s *windowsService) Execute(serviceArgs []string, r <-chan svc.ChangeReques
func installWindowsService(c *cli.Context) error { func installWindowsService(c *cli.Context) error {
zeroLogger := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog) zeroLogger := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
zeroLogger.Info().Msg("Installing Cloudflare Tunnel Windows service") zeroLogger.Info().Msg("Installing cloudflared Windows service")
exepath, err := os.Executable() exepath, err := os.Executable()
if err != nil { if err != nil {
return errors.Wrap(err, "Cannot find path name that start the process") return errors.Wrap(err, "Cannot find path name that start the process")
@ -206,7 +206,7 @@ func installWindowsService(c *cli.Context) error {
return errors.Wrap(err, "Cannot install service") return errors.Wrap(err, "Cannot install service")
} }
defer s.Close() defer s.Close()
log.Info().Msg("Cloudflare Tunnel agent service is installed") log.Info().Msg("cloudflared agent service is installed")
err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info) err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil { if err != nil {
s.Delete() s.Delete()
@ -219,7 +219,11 @@ func installWindowsService(c *cli.Context) error {
log.Info().Msgf("See %s to manually configure service recovery actions", windowsServiceUrl) log.Info().Msgf("See %s to manually configure service recovery actions", windowsServiceUrl)
} }
return s.Start() err = s.Start()
if err == nil {
log.Info().Msg("Agent service for cloudflared installed successfully")
}
return err
} }
func uninstallWindowsService(c *cli.Context) error { func uninstallWindowsService(c *cli.Context) error {
@ -227,7 +231,7 @@ func uninstallWindowsService(c *cli.Context) error {
With(). With().
Str(LogFieldWindowsServiceName, windowsServiceName).Logger() Str(LogFieldWindowsServiceName, windowsServiceName).Logger()
log.Info().Msg("Uninstalling Cloudflare Tunnel Windows Service") log.Info().Msg("Uninstalling cloudflared agent service")
m, err := mgr.Connect() m, err := mgr.Connect()
if err != nil { if err != nil {
return errors.Wrap(err, "Cannot establish a connection to the service control manager") return errors.Wrap(err, "Cannot establish a connection to the service control manager")
@ -235,22 +239,22 @@ func uninstallWindowsService(c *cli.Context) error {
defer m.Disconnect() defer m.Disconnect()
s, err := m.OpenService(windowsServiceName) s, err := m.OpenService(windowsServiceName)
if err != nil { if err != nil {
return fmt.Errorf("Service %s is not installed", windowsServiceName) return fmt.Errorf("Agent service %s is not installed, so it could not be uninstalled", windowsServiceName)
} }
defer s.Close() defer s.Close()
if status, err := s.Query(); err == nil && status.State == svc.Running { if status, err := s.Query(); err == nil && status.State == svc.Running {
log.Info().Msg("Stopping Cloudflare Tunnel agent service") log.Info().Msg("Stopping cloudflared agent service")
if _, err := s.Control(svc.Stop); err != nil { if _, err := s.Control(svc.Stop); err != nil {
log.Info().Err(err).Msg("Failed to stop Cloudflare Tunnel agent service, you may need to stop it manually to complete uninstall.") log.Info().Err(err).Msg("Failed to stop cloudflared agent service, you may need to stop it manually to complete uninstall.")
} }
} }
err = s.Delete() err = s.Delete()
if err != nil { if err != nil {
return errors.Wrap(err, "Cannot delete service") return errors.Wrap(err, "Cannot delete agent service")
} }
log.Info().Msg("Cloudflare Tunnel agent service is uninstalled") log.Info().Msg("Agent service for cloudflared was uninstalled successfully")
err = eventlog.Remove(windowsServiceName) err = eventlog.Remove(windowsServiceName)
if err != nil { if err != nil {
return errors.Wrap(err, "Cannot remove event logger") return errors.Wrap(err, "Cannot remove event logger")