Release Argo Tunnel Client 2018.5.4

This commit is contained in:
cloudflare-warp-bot 2018-05-14 23:55:55 +00:00
parent 9135a4837c
commit 75d7561b5d
8 changed files with 193 additions and 83 deletions

View File

@ -11,6 +11,7 @@ import (
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"time"
@ -113,11 +114,13 @@ func enoughOptionsSet(c *cli.Context) bool {
return true
}
func handleDeprecatedOptions(c *cli.Context) {
func handleDeprecatedOptions(c *cli.Context) error {
// Fail if the user provided an old authentication method
if c.IsSet("api-key") || c.IsSet("api-email") || c.IsSet("api-ca-key") {
logger.Fatal("You don't need to give us your api-key anymore. Please use the new login method. Just run cloudflared login")
logger.Error("You don't need to give us your api-key anymore. Please use the new login method. Just run cloudflared login")
return fmt.Errorf("Client provided deprecated options")
}
return nil
}
// validate url. It can be either from --url or argument
@ -162,26 +165,30 @@ func dnsProxyStandAlone(c *cli.Context) bool {
return c.IsSet("proxy-dns") && (!c.IsSet("hostname") && !c.IsSet("tag") && !c.IsSet("hello-world"))
}
func getOriginCert(c *cli.Context) []byte {
func getOriginCert(c *cli.Context) ([]byte, error) {
if c.String("origincert") == "" {
logger.Warnf("Cannot determine default origin certificate path. No file %s in %v", defaultCredentialFile, defaultConfigDirs)
if isRunningFromTerminal() {
logger.Fatalf("You need to specify the origin certificate path with --origincert option, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", argumentsUrl)
logger.Errorf("You need to specify the origin certificate path with --origincert option, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", argumentsUrl)
return nil, fmt.Errorf("Client didn't specify origincert path when running from terminal")
} else {
logger.Fatalf("You need to specify the origin certificate path by specifying the origincert option in the configuration file, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", serviceUrl)
logger.Errorf("You need to specify the origin certificate path by specifying the origincert option in the configuration file, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", serviceUrl)
return nil, fmt.Errorf("Client didn't specify origincert path")
}
}
// Check that the user has acquired a certificate using the login command
originCertPath, err := homedir.Expand(c.String("origincert"))
if err != nil {
logger.WithError(err).Fatalf("Cannot resolve path %s", c.String("origincert"))
logger.WithError(err).Errorf("Cannot resolve path %s", c.String("origincert"))
return nil, fmt.Errorf("Cannot resolve path %s", c.String("origincert"))
}
ok, err := fileExists(originCertPath)
if err != nil {
logger.Fatalf("Cannot check if origin cert exists at path %s", c.String("origincert"))
logger.Errorf("Cannot check if origin cert exists at path %s", c.String("origincert"))
return nil, fmt.Errorf("Cannot check if origin cert exists at path %s", c.String("origincert"))
}
if !ok {
logger.Fatalf(`Cannot find a valid certificate for your origin at the path:
logger.Errorf(`Cannot find a valid certificate for your origin at the path:
%s
@ -190,19 +197,22 @@ If you don't have a certificate signed by Cloudflare, run the command:
%s login
`, originCertPath, os.Args[0])
return nil, fmt.Errorf("Cannot find a valid certificate at the path %s", originCertPath)
}
// Easier to send the certificate as []byte via RPC than decoding it at this point
originCert, err := ioutil.ReadFile(originCertPath)
if err != nil {
logger.WithError(err).Fatalf("Cannot read %s to load origin certificate", originCertPath)
logger.WithError(err).Errorf("Cannot read %s to load origin certificate", originCertPath)
return nil, fmt.Errorf("Cannot read %s to load origin certificate", originCertPath)
}
return originCert
return originCert, nil
}
func prepareTunnelConfig(c *cli.Context, buildInfo *origin.BuildInfo, logger, protoLogger *logrus.Logger) *origin.TunnelConfig {
func prepareTunnelConfig(c *cli.Context, buildInfo *origin.BuildInfo, logger, protoLogger *logrus.Logger) (*origin.TunnelConfig, error) {
hostname, err := validation.ValidateHostname(c.String("hostname"))
if err != nil {
logger.WithError(err).Fatal("Invalid hostname")
logger.WithError(err).Error("Invalid hostname")
return nil, errors.Wrap(err, "Invalid hostname")
}
clientID := c.String("id")
if !c.IsSet("id") {
@ -211,22 +221,28 @@ func prepareTunnelConfig(c *cli.Context, buildInfo *origin.BuildInfo, logger, pr
tags, err := NewTagSliceFromCLI(c.StringSlice("tag"))
if err != nil {
logger.WithError(err).Fatal("Tag parse failure")
logger.WithError(err).Error("Tag parse failure")
return nil, errors.Wrap(err, "Tag parse failure")
}
tags = append(tags, tunnelpogs.Tag{Name: "ID", Value: clientID})
url, err := validateUrl(c)
if err != nil {
logger.WithError(err).Fatal("Error validating url")
logger.WithError(err).Error("Error validating url")
return nil, errors.Wrap(err, "Error validating url")
}
logger.Infof("Proxying tunnel requests to %s", url)
originCert := getOriginCert(c)
originCertPool, err := loadCertPool(c)
originCert, err := getOriginCert(c)
if err != nil {
logger.Fatal(err)
return nil, errors.Wrap(err, "Error getting origin cert")
}
originCertPool, err := loadCertPool(c, logger)
if err != nil {
logger.WithError(err).Error("Error loading cert pool")
return nil, errors.Wrap(err, "Error loading cert pool")
}
tunnelMetrics := origin.NewTunnelMetrics()
@ -272,10 +288,10 @@ func prepareTunnelConfig(c *cli.Context, buildInfo *origin.BuildInfo, logger, pr
IsAutoupdated: c.Bool("is-autoupdated"),
GracePeriod: c.Duration("grace-period"),
RunFromTerminal: isRunningFromTerminal(),
}
}, nil
}
func loadCertPool(c *cli.Context) (*x509.CertPool, error) {
func loadCertPool(c *cli.Context, logger *logrus.Logger) (*x509.CertPool, error) {
const originCAPoolFlag = "origin-ca-pool"
originCAPoolFilename := c.String(originCAPoolFlag)
var originCustomCAPool []byte
@ -293,5 +309,10 @@ func loadCertPool(c *cli.Context) (*x509.CertPool, error) {
return nil, errors.Wrap(err, "error loading the certificate pool")
}
// Windows users should be notified that they can use the flag
if runtime.GOOS == "windows" && originCAPoolFilename == "" {
logger.Infof("cloudflared does not support loading the system root certificate pool on Windows. Please use the --%s to specify it", originCAPoolFlag)
}
return originCertPool, nil
}

View File

@ -16,22 +16,25 @@ import (
var logger = log.CreateLogger()
func configMainLogger(c *cli.Context) {
func configMainLogger(c *cli.Context) error {
logLevel, err := logrus.ParseLevel(c.String("loglevel"))
if err != nil {
logger.WithError(err).Fatal("Unknown logging level specified")
logger.WithError(err).Error("Unknown logging level specified")
return errors.Wrap(err, "Unknown logging level specified")
}
logger.SetLevel(logLevel)
return nil
}
func configProtoLogger(c *cli.Context) *logrus.Logger {
func configProtoLogger(c *cli.Context) (*logrus.Logger, error) {
protoLogLevel, err := logrus.ParseLevel(c.String("proto-loglevel"))
if err != nil {
logger.WithError(err).Fatal("Unknown protocol logging level specified")
return nil, errors.Wrap(err, "Unknown protocol logging level specified")
}
protoLogger := logrus.New()
protoLogger.Level = protoLogLevel
return protoLogger
return protoLogger, nil
}
func initLogFile(c *cli.Context, loggers ...*logrus.Logger) error {

View File

@ -7,6 +7,8 @@ import (
"os"
"gopkg.in/urfave/cli.v2"
"github.com/pkg/errors"
)
const (
@ -33,9 +35,10 @@ func runApp(app *cli.App, shutdownC chan struct{}) {
app.Run(os.Args)
}
var launchdTemplate = ServiceTemplate{
Path: installPath(),
Content: fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
func newLaunchdTemplate(installPath, stdoutPath, stderrPath string) *ServiceTemplate {
return &ServiceTemplate{
Path: installPath,
Content: fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
@ -59,33 +62,46 @@ var launchdTemplate = ServiceTemplate{
<key>ThrottleInterval</key>
<integer>20</integer>
</dict>
</plist>`, launchdIdentifier, stdoutPath(), stderrPath()),
</plist>`, launchdIdentifier, stdoutPath, stderrPath),
}
}
func isRootUser() bool {
return os.Geteuid() == 0
}
func installPath() string {
func installPath() (string, error) {
// User is root, use /Library/LaunchDaemons instead of home directory
if isRootUser() {
return fmt.Sprintf("/Library/LaunchDaemons/%s.plist", launchdIdentifier)
return fmt.Sprintf("/Library/LaunchDaemons/%s.plist", launchdIdentifier), nil
}
return fmt.Sprintf("%s/Library/LaunchAgents/%s.plist", userHomeDir(), launchdIdentifier)
userHomeDir, err := userHomeDir()
if err != nil {
return "", err
}
return fmt.Sprintf("%s/Library/LaunchAgents/%s.plist", userHomeDir, launchdIdentifier), nil
}
func stdoutPath() string {
func stdoutPath() (string, error) {
if isRootUser() {
return fmt.Sprintf("/Library/Logs/%s.out.log", launchdIdentifier)
return fmt.Sprintf("/Library/Logs/%s.out.log", launchdIdentifier), nil
}
return fmt.Sprintf("%s/Library/Logs/%s.out.log", userHomeDir(), launchdIdentifier)
userHomeDir, err := userHomeDir()
if err != nil {
return "", err
}
return fmt.Sprintf("%s/Library/Logs/%s.out.log", userHomeDir, launchdIdentifier), nil
}
func stderrPath() string {
func stderrPath() (string, error) {
if isRootUser() {
return fmt.Sprintf("/Library/Logs/%s.err.log", launchdIdentifier)
return fmt.Sprintf("/Library/Logs/%s.err.log", launchdIdentifier), nil
}
return fmt.Sprintf("%s/Library/Logs/%s.err.log", userHomeDir(), launchdIdentifier)
userHomeDir, err := userHomeDir()
if err != nil {
return "", err
}
return fmt.Sprintf("%s/Library/Logs/%s.err.log", userHomeDir, launchdIdentifier), nil
}
func installLaunchd(c *cli.Context) error {
@ -100,13 +116,30 @@ func installLaunchd(c *cli.Context) error {
}
etPath, err := os.Executable()
if err != nil {
logger.WithError(err).Infof("error determining executable path")
return fmt.Errorf("error determining executable path: %v", err)
logger.WithError(err).Errorf("Error determining executable path")
return fmt.Errorf("Error determining executable path: %v", err)
}
installPath, err := installPath()
if err != nil {
return errors.Wrap(err, "Error determining install path")
}
stdoutPath, err := stdoutPath()
if err != nil {
return errors.Wrap(err, "error determining stdout path")
}
stderrPath, err := stderrPath()
if err != nil {
return errors.Wrap(err, "error determining stderr path")
}
launchdTemplate := newLaunchdTemplate(installPath, stdoutPath, stderrPath)
if err != nil {
logger.WithError(err).Errorf("error creating launchd template")
return errors.Wrap(err, "error creating launchd template")
}
templateArgs := ServiceTemplateArgs{Path: etPath}
err = launchdTemplate.Generate(&templateArgs)
if err != nil {
logger.WithError(err).Infof("error generating launchd template")
logger.WithError(err).Errorf("error generating launchd template")
return err
}
plistPath, err := launchdTemplate.ResolvePath()
@ -115,7 +148,7 @@ func installLaunchd(c *cli.Context) error {
return err
}
logger.Infof("Outputs are logged to %s and %s", stderrPath(), stdoutPath())
logger.Infof("Outputs are logged to %s and %s", stderrPath, stdoutPath)
return runCommand("launchctl", "load", plistPath)
}
@ -125,6 +158,22 @@ func uninstallLaunchd(c *cli.Context) error {
} else {
logger.Infof("Uninstalling Argo Tunnel as an user launch agent")
}
installPath, err := installPath()
if err != nil {
return errors.Wrap(err, "error determining install path")
}
stdoutPath, err := stdoutPath()
if err != nil {
return errors.Wrap(err, "error determining stdout path")
}
stderrPath, err := stderrPath()
if err != nil {
return errors.Wrap(err, "error determining stderr path")
}
launchdTemplate := newLaunchdTemplate(installPath, stdoutPath, stderrPath)
if err != nil {
return errors.Wrap(err, "error creating launchd template")
}
plistPath, err := launchdTemplate.ResolvePath()
if err != nil {
logger.WithError(err).Infof("error resolving launchd template path")
@ -136,6 +185,6 @@ func uninstallLaunchd(c *cli.Context) error {
return err
}
logger.Infof("Outputs are logged to %s and %s", stderrPath(), stdoutPath())
logger.Infof("Outputs are logged to %s and %s", stderrPath, stdoutPath)
return launchdTemplate.Remove()
}

View File

@ -18,6 +18,7 @@ import (
"github.com/coreos/go-systemd/daemon"
"github.com/facebookgo/grace/gracenet"
"github.com/pkg/errors"
)
const (
@ -275,9 +276,15 @@ func main() {
Hidden: true,
}),
}
app.Action = func(c *cli.Context) error {
raven.CapturePanic(func() { startServer(c, shutdownC) }, nil)
return nil
app.Action = func(c *cli.Context) (err error) {
tags := make(map[string]string)
tags["hostname"] = c.String("hostname")
raven.SetTagsContext(tags)
raven.CapturePanicAndWait(func() { err = startServer(c, shutdownC) }, nil)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
}
return err
}
app.Before = func(context *cli.Context) error {
if context.String("config") == "" {
@ -370,7 +377,7 @@ func main() {
runApp(app, shutdownC)
}
func startServer(c *cli.Context, shutdownC chan struct{}) {
func startServer(c *cli.Context, shutdownC chan struct{}) error {
var wg sync.WaitGroup
listeners := gracenet.Net{}
errC := make(chan error)
@ -380,18 +387,26 @@ func startServer(c *cli.Context, shutdownC chan struct{}) {
// check whether client provides enough flags or env variables. If not, print help.
if ok := enoughOptionsSet(c); !ok {
return
return nil
}
configMainLogger(c)
protoLogger := configProtoLogger(c)
if err := configMainLogger(c); err != nil {
return errors.Wrap(err, "Error configuring logger")
}
protoLogger, err := configProtoLogger(c)
if err != nil {
return errors.Wrap(err, "Error configuring protocol logger")
}
if c.String("logfile") != "" {
if err := initLogFile(c, logger, protoLogger); err != nil {
logger.Error(err)
}
}
handleDeprecatedOptions(c)
if err := handleDeprecatedOptions(c); err != nil {
return err
}
buildInfo := origin.GetBuildInfo()
logger.Infof("Build info: %+v", *buildInfo)
@ -402,7 +417,7 @@ func startServer(c *cli.Context, shutdownC chan struct{}) {
wg.Add(1)
go func() {
defer wg.Done()
runDNSProxyServer(c, dnsReadySignal, shutdownC)
errC <- runDNSProxyServer(c, dnsReadySignal, shutdownC)
}()
} else {
close(dnsReadySignal)
@ -414,15 +429,20 @@ func startServer(c *cli.Context, shutdownC chan struct{}) {
// update needs to be after DNS proxy is up to resolve equinox server address
if isAutoupdateEnabled(c) {
if initUpdate(&listeners) {
return
return nil
}
logger.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
go autoupdate(c.Duration("autoupdate-freq"), &listeners, shutdownC)
wg.Add(1)
go func(){
defer wg.Done()
autoupdate(c.Duration("autoupdate-freq"), &listeners, shutdownC)
}()
}
metricsListener, err := listeners.Listen("tcp", c.String("metrics"))
if err != nil {
logger.WithError(err).Fatal("Error opening metrics server listener")
logger.WithError(err).Error("Error opening metrics server listener")
return errors.Wrap(err, "Error opening metrics server listener")
}
defer metricsListener.Close()
wg.Add(1)
@ -438,14 +458,14 @@ func startServer(c *cli.Context, shutdownC chan struct{}) {
close(connectedSignal)
}
// no grace period, handle SIGINT/SIGTERM immediately
waitToShutdown(&wg, errC, shutdownC, graceShutdownSignal, 0)
return
return waitToShutdown(&wg, errC, shutdownC, graceShutdownSignal, 0)
}
if c.IsSet("hello-world") {
helloListener, err := hello.CreateTLSListener("127.0.0.1:")
if err != nil {
logger.WithError(err).Fatal("Cannot start Hello World Server")
logger.WithError(err).Error("Cannot start Hello World Server")
return errors.Wrap(err, "Cannot start Hello World Server")
}
defer helloListener.Close()
wg.Add(1)
@ -456,7 +476,10 @@ func startServer(c *cli.Context, shutdownC chan struct{}) {
c.Set("url", "https://"+helloListener.Addr().String())
}
tunnelConfig := prepareTunnelConfig(c, buildInfo, logger, protoLogger)
tunnelConfig, err := prepareTunnelConfig(c, buildInfo, logger, protoLogger)
if err != nil {
return err
}
if c.IsSet("pidFile") {
go writePidFile(connectedSignal, c.String("pidfile"))
@ -468,14 +491,14 @@ func startServer(c *cli.Context, shutdownC chan struct{}) {
errC <- origin.StartTunnelDaemon(tunnelConfig, graceShutdownSignal, connectedSignal)
}()
waitToShutdown(&wg, errC, shutdownC, graceShutdownSignal, c.Duration("grace-period"))
return waitToShutdown(&wg, errC, shutdownC, graceShutdownSignal, c.Duration("grace-period"))
}
func waitToShutdown(wg *sync.WaitGroup,
errC chan error,
shutdownC, graceShutdownSignal chan struct{},
gracePeriod time.Duration,
) {
) error {
var err error
if gracePeriod > 0 {
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceShutdownSignal, gracePeriod)
@ -484,11 +507,8 @@ func waitToShutdown(wg *sync.WaitGroup,
close(graceShutdownSignal)
}
var errCode int
if err != nil {
logger.WithError(err).Fatal("Quitting due to error")
raven.CaptureErrorAndWait(err, nil)
errCode = 1
logger.WithError(err).Error("Quitting due to error")
} else {
logger.Info("Quitting...")
}
@ -498,7 +518,7 @@ func waitToShutdown(wg *sync.WaitGroup,
}
}()
wg.Wait()
os.Exit(errCode)
return err
}
func writePidFile(waitForSignal chan struct{}, pidFile string) {
@ -515,14 +535,15 @@ func writePidFile(waitForSignal chan struct{}, pidFile string) {
fmt.Fprintf(file, "%d", os.Getpid())
}
func userHomeDir() string {
func userHomeDir() (string, error) {
// This returns the home dir of the executing user using OS-specific method
// for discovering the home dir. It's not recommended to call this function
// when the user has root permission as $HOME depends on what options the user
// use with sudo.
homeDir, err := homedir.Dir()
if err != nil {
logger.WithError(err).Fatal("Cannot determine home directory for the user.")
logger.WithError(err).Error("Cannot determine home directory for the user")
return "", errors.Wrap(err, "Cannot determine home directory for the user")
}
return homeDir
return homeDir, nil
}

View File

@ -4,24 +4,30 @@ import (
"github.com/cloudflare/cloudflared/tunneldns"
"gopkg.in/urfave/cli.v2"
"github.com/pkg/errors"
)
func runDNSProxyServer(c *cli.Context, dnsReadySignal, shutdownC chan struct{}) {
func runDNSProxyServer(c *cli.Context, dnsReadySignal, shutdownC chan struct{}) error {
port := c.Int("proxy-dns-port")
if port <= 0 || port > 65535 {
logger.Fatal("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
logger.Errorf("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
return errors.New("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
}
listener, err := tunneldns.CreateListener(c.String("proxy-dns-address"), uint16(port), c.StringSlice("proxy-dns-upstream"))
if err != nil {
close(dnsReadySignal)
listener.Stop()
logger.WithError(err).Fatal("Cannot create the DNS over HTTPS proxy server")
logger.WithError(err).Error("Cannot create the DNS over HTTPS proxy server")
return errors.Wrap(err, "Cannot create the DNS over HTTPS proxy server")
}
err = listener.Start(dnsReadySignal)
if err != nil {
logger.WithError(err).Fatal("Cannot start the DNS over HTTPS proxy server")
logger.WithError(err).Error("Cannot start the DNS over HTTPS proxy server")
return errors.Wrap(err, "Cannot start the DNS over HTTPS proxy server")
}
<-shutdownC
listener.Stop()
return nil
}

View File

@ -2,6 +2,7 @@ package main
import (
"os"
"runtime"
"time"
"golang.org/x/crypto/ssh/terminal"
@ -12,8 +13,9 @@ import (
)
const (
appID = "app_idCzgxYerVD"
noAutoupdateMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/"
appID = "app_idCzgxYerVD"
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/"
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
)
var publicKey = []byte(`
@ -98,8 +100,13 @@ func updateApplied() bool {
}
func isAutoupdateEnabled(c *cli.Context) bool {
if runtime.GOOS == "windows" {
logger.Info(noUpdateOnWindowsMessage)
return false
}
if isRunningFromTerminal() {
logger.Info(noAutoupdateMessage)
logger.Info(noUpdateInShellMessage)
return false
}

View File

@ -51,7 +51,7 @@ func runApp(app *cli.App, shutdownC chan struct{}) {
elog, err := eventlog.Open(windowsServiceName)
if err != nil {
logger.WithError(err).Infof("Cannot open event log for %s", windowsServiceName)
logger.WithError(err).Errorf("Cannot open event log for %s", windowsServiceName)
return
}
defer elog.Close()
@ -108,12 +108,12 @@ func installWindowsService(c *cli.Context) error {
logger.Infof("Installing Argo Tunnel Windows service")
exepath, err := os.Executable()
if err != nil {
logger.Infof("Cannot find path name that start the process")
logger.Errorf("Cannot find path name that start the process")
return err
}
m, err := mgr.Connect()
if err != nil {
logger.WithError(err).Infof("Cannot establish a connection to the service control manager")
logger.WithError(err).Errorf("Cannot establish a connection to the service control manager")
return err
}
defer m.Disconnect()
@ -126,14 +126,14 @@ func installWindowsService(c *cli.Context) error {
config := mgr.Config{StartType: mgr.StartAutomatic, DisplayName: windowsServiceDescription}
s, err = m.CreateService(windowsServiceName, exepath, config)
if err != nil {
logger.Infof("Cannot install service %s", windowsServiceName)
logger.Errorf("Cannot install service %s", windowsServiceName)
return err
}
defer s.Close()
err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil {
s.Delete()
logger.WithError(err).Infof("Cannot install event logger")
logger.WithError(err).Errorf("Cannot install event logger")
return fmt.Errorf("SetupEventLogSource() failed: %s", err)
}
return nil
@ -143,13 +143,13 @@ func uninstallWindowsService(c *cli.Context) error {
logger.Infof("Uninstalling Argo Tunnel Windows Service")
m, err := mgr.Connect()
if err != nil {
logger.Infof("Cannot establish a connection to the service control manager")
logger.Errorf("Cannot establish a connection to the service control manager")
return err
}
defer m.Disconnect()
s, err := m.OpenService(windowsServiceName)
if err != nil {
logger.Infof("service %s is not installed", windowsServiceName)
logger.Errorf("service %s is not installed", windowsServiceName)
return fmt.Errorf("service %s is not installed", windowsServiceName)
}
defer s.Close()
@ -160,7 +160,7 @@ func uninstallWindowsService(c *cli.Context) error {
}
err = eventlog.Remove(windowsServiceName)
if err != nil {
logger.Infof("Cannot remove event logger")
logger.Errorf("Cannot remove event logger")
return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
}
return nil

View File

@ -1,3 +1,6 @@
// +build ignore
// TODO: Remove the above build tag and include this test when we start compiling with Golang 1.10.0+
package tlsconfig
import (