AUTH-2596 added new logger package and replaced logrus

This commit is contained in:
Dalton
2020-04-29 15:51:32 -05:00
parent a908453aa4
commit 046be63253
158 changed files with 2027 additions and 5771 deletions

View File

@@ -8,22 +8,23 @@ import (
"github.com/cloudflare/cloudflared/carrier"
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/h2mux"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/validation"
"github.com/pkg/errors"
cli "gopkg.in/urfave/cli.v2"
)
// StartForwarder starts a client side websocket forward
func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}) error {
func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}, logger logger.Service) error {
validURLString, err := validation.ValidateUrl(forwarder.Listener)
if err != nil {
logger.WithError(err).Error("Error validating origin URL")
logger.Errorf("Error validating origin URL: %s", err)
return errors.Wrap(err, "error validating origin URL")
}
validURL, err := url.Parse(validURLString)
if err != nil {
logger.WithError(err).Error("Error parsing origin URL")
logger.Errorf("Error parsing origin URL: %s", err)
return errors.Wrap(err, "error parsing origin URL")
}
@@ -44,6 +45,12 @@ func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}) error
// useful for proxying other protocols (like ssh) over websockets
// (which you can put Access in front of)
func ssh(c *cli.Context) error {
logDirectory, logLevel := config.FindLogSettings()
logger, err := logger.New(logger.DefaultFile(logDirectory), logger.LogLevelString(logLevel))
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
// get the hostname from the cmdline and error out if its not provided
rawHostName := c.String(sshHostnameFlag)
hostname, err := validation.ValidateHostname(rawHostName)
@@ -77,17 +84,21 @@ func ssh(c *cli.Context) error {
if c.NArg() > 0 || c.IsSet(sshURLFlag) {
localForwarder, err := config.ValidateUrl(c)
if err != nil {
logger.WithError(err).Error("Error validating origin URL")
logger.Errorf("Error validating origin URL: %s", err)
return errors.Wrap(err, "error validating origin URL")
}
forwarder, err := url.Parse(localForwarder)
if err != nil {
logger.WithError(err).Error("Error validating origin URL")
logger.Errorf("Error validating origin URL: %s", err)
return errors.Wrap(err, "error validating origin URL")
}
logger.Infof("Start Websocket listener on: %s", forwarder.Host)
return carrier.StartForwarder(wsConn, forwarder.Host, shutdownC, options)
err = carrier.StartForwarder(wsConn, forwarder.Host, shutdownC, options)
if err != nil {
logger.Errorf("Error on Websocket listener: %s", err)
}
return err
}
return carrier.StartClient(wsConn, &carrier.StdinoutStream{}, options)

View File

@@ -14,12 +14,12 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/shell"
"github.com/cloudflare/cloudflared/cmd/cloudflared/token"
"github.com/cloudflare/cloudflared/h2mux"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/sshgen"
"github.com/cloudflare/cloudflared/validation"
"github.com/pkg/errors"
"golang.org/x/net/idna"
"github.com/cloudflare/cloudflared/log"
"github.com/getsentry/raven-go"
"gopkg.in/urfave/cli.v2"
)
@@ -53,7 +53,6 @@ Host cfpipe-{{.Hostname}}
const sentryDSN = "https://56a9c9fa5c364ab28f34b14f35ea0f1b@sentry.io/189878"
var (
logger = log.CreateLogger()
shutdownC chan struct{}
graceShutdownC chan struct{}
)
@@ -195,7 +194,12 @@ func login(c *cli.Context) error {
if err := raven.SetDSN(sentryDSN); err != nil {
return err
}
logger := log.CreateLogger()
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
args := c.Args()
rawURL := ensureURLScheme(args.First())
appURL, err := url.Parse(rawURL)
@@ -203,8 +207,8 @@ func login(c *cli.Context) error {
logger.Errorf("Please provide the url of the Access application\n")
return err
}
if err := verifyTokenAtEdge(appURL, c); err != nil {
logger.WithError(err).Error("Could not verify token")
if err := verifyTokenAtEdge(appURL, c, logger); err != nil {
logger.Errorf("Could not verify token: %s", err)
return err
}
@@ -236,7 +240,11 @@ func curl(c *cli.Context) error {
if err := raven.SetDSN(sentryDSN); err != nil {
return err
}
logger := log.CreateLogger()
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
args := c.Args()
if args.Len() < 1 {
logger.Error("Please provide the access app and command you wish to run.")
@@ -244,7 +252,7 @@ func curl(c *cli.Context) error {
}
cmdArgs, allowRequest := parseAllowRequest(args.Slice())
appURL, err := getAppURL(cmdArgs)
appURL, err := getAppURL(cmdArgs, logger)
if err != nil {
return err
}
@@ -252,12 +260,12 @@ func curl(c *cli.Context) error {
tok, err := token.GetTokenIfExists(appURL)
if err != nil || tok == "" {
if allowRequest {
logger.Warn("You don't have an Access token set. Please run access token <access application> to fetch one.")
logger.Info("You don't have an Access token set. Please run access token <access application> to fetch one.")
return shell.Run("curl", cmdArgs...)
}
tok, err = token.FetchToken(appURL)
tok, err = token.FetchToken(appURL, logger)
if err != nil {
logger.Error("Failed to refresh token: ", err)
logger.Errorf("Failed to refresh token: %s", err)
return err
}
}
@@ -311,6 +319,11 @@ func sshConfig(c *cli.Context) error {
// sshGen generates a short lived certificate for provided hostname
func sshGen(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
// get the hostname from the cmdline and error out if its not provided
rawHostName := c.String(sshHostnameFlag)
hostname, err := validation.ValidateHostname(rawHostName)
@@ -326,7 +339,7 @@ func sshGen(c *cli.Context) error {
// this fetchToken function mutates the appURL param. We should refactor that
fetchTokenURL := &url.URL{}
*fetchTokenURL = *originURL
cfdToken, err := token.FetchToken(fetchTokenURL)
cfdToken, err := token.FetchToken(fetchTokenURL, logger)
if err != nil {
return err
}
@@ -339,7 +352,7 @@ func sshGen(c *cli.Context) error {
}
// getAppURL will pull the appURL needed for fetching a user's Access token
func getAppURL(cmdArgs []string) (*url.URL, error) {
func getAppURL(cmdArgs []string, logger logger.Service) (*url.URL, error) {
if len(cmdArgs) < 1 {
logger.Error("Please provide a valid URL as the first argument to curl.")
return nil, errors.New("not a valid url")
@@ -413,7 +426,7 @@ func isFileThere(candidate string) bool {
// verifyTokenAtEdge checks for a token on disk, or generates a new one.
// Then makes a request to to the origin with the token to ensure it is valid.
// Returns nil if token is valid.
func verifyTokenAtEdge(appUrl *url.URL, c *cli.Context) error {
func verifyTokenAtEdge(appUrl *url.URL, c *cli.Context, logger logger.Service) error {
headers := buildRequestHeaders(c.StringSlice(sshHeaderFlag))
if c.IsSet(sshTokenIDFlag) {
headers.Add(h2mux.CFAccessClientIDHeader, c.String(sshTokenIDFlag))
@@ -423,7 +436,7 @@ func verifyTokenAtEdge(appUrl *url.URL, c *cli.Context) error {
}
options := &carrier.StartOptions{OriginURL: appUrl.String(), Headers: headers}
if valid, err := isTokenValid(options); err != nil {
if valid, err := isTokenValid(options, logger); err != nil {
return err
} else if valid {
return nil
@@ -433,7 +446,7 @@ func verifyTokenAtEdge(appUrl *url.URL, c *cli.Context) error {
return err
}
if valid, err := isTokenValid(options); err != nil {
if valid, err := isTokenValid(options, logger); err != nil {
return err
} else if !valid {
return errors.New("failed to verify token")
@@ -443,8 +456,8 @@ func verifyTokenAtEdge(appUrl *url.URL, c *cli.Context) error {
}
// isTokenValid makes a request to the origin and returns true if the response was not a 302.
func isTokenValid(options *carrier.StartOptions) (bool, error) {
req, err := carrier.BuildAccessRequest(options)
func isTokenValid(options *carrier.StartOptions, logger logger.Service) (bool, error) {
req, err := carrier.BuildAccessRequest(options, logger)
if err != nil {
return false, errors.Wrap(err, "Could not create access request")
}

View File

@@ -3,6 +3,7 @@ package main
import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/access"
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
)
// ForwardServiceType is used to identify what kind of overwatch service this is
@@ -14,11 +15,12 @@ const ForwardServiceType = "forward"
type ForwarderService struct {
forwarder config.Forwarder
shutdown chan struct{}
logger logger.Service
}
// NewForwardService creates a new forwarder service
func NewForwardService(f config.Forwarder) *ForwarderService {
return &ForwarderService{forwarder: f, shutdown: make(chan struct{}, 1)}
func NewForwardService(f config.Forwarder, logger logger.Service) *ForwarderService {
return &ForwarderService{forwarder: f, shutdown: make(chan struct{}, 1), logger: logger}
}
// Name is used to figure out this service is related to the others (normally the addr it binds to)
@@ -44,5 +46,5 @@ func (s *ForwarderService) Shutdown() {
// Run is the run loop that is started by the overwatch service
func (s *ForwarderService) Run() error {
return access.StartForwarder(s.forwarder, s.shutdown)
return access.StartForwarder(s.forwarder, s.shutdown, s.logger)
}

View File

@@ -2,8 +2,8 @@ package main
import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/tunneldns"
"github.com/sirupsen/logrus"
)
// ResolverServiceType is used to identify what kind of overwatch service this is
@@ -15,11 +15,11 @@ const ResolverServiceType = "resolver"
type ResolverService struct {
resolver config.DNSResolver
shutdown chan struct{}
logger *logrus.Logger
logger logger.Service
}
// NewResolverService creates a new resolver service
func NewResolverService(r config.DNSResolver, logger *logrus.Logger) *ResolverService {
func NewResolverService(r config.DNSResolver, logger logger.Service) *ResolverService {
return &ResolverService{resolver: r,
shutdown: make(chan struct{}),
logger: logger,
@@ -51,7 +51,7 @@ func (s *ResolverService) Shutdown() {
func (s *ResolverService) Run() error {
// create a listener
l, err := tunneldns.CreateListener(s.resolver.AddressOrDefault(), s.resolver.PortOrDefault(),
s.resolver.UpstreamsOrDefault(), s.resolver.BootstrapsOrDefault())
s.resolver.UpstreamsOrDefault(), s.resolver.BootstrapsOrDefault(), s.logger)
if err != nil {
return err
}

View File

@@ -2,8 +2,8 @@ package main
import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/overwatch"
"github.com/sirupsen/logrus"
)
// AppService is the main service that runs when no command lines flags are passed to cloudflared
@@ -13,11 +13,11 @@ type AppService struct {
serviceManager overwatch.Manager
shutdownC chan struct{}
configUpdateChan chan config.Root
logger *logrus.Logger
logger logger.Service
}
// NewAppService creates a new AppService with needed supporting services
func NewAppService(configManager config.Manager, serviceManager overwatch.Manager, shutdownC chan struct{}, logger *logrus.Logger) *AppService {
func NewAppService(configManager config.Manager, serviceManager overwatch.Manager, shutdownC chan struct{}, logger logger.Service) *AppService {
return &AppService{
configManager: configManager,
serviceManager: serviceManager,
@@ -66,7 +66,7 @@ func (s *AppService) handleConfigUpdate(c config.Root) {
// handle the client forward listeners
activeServices := map[string]struct{}{}
for _, f := range c.Forwarders {
service := NewForwardService(f)
service := NewForwardService(f, s.logger)
s.serviceManager.Add(service)
activeServices[service.Name()] = struct{}{}
}

View File

@@ -3,7 +3,7 @@ package buildinfo
import (
"runtime"
"github.com/sirupsen/logrus"
"github.com/cloudflare/cloudflared/logger"
)
type BuildInfo struct {
@@ -22,7 +22,7 @@ func GetBuildInfo(cloudflaredVersion string) *BuildInfo {
}
}
func (bi *BuildInfo) Log(logger *logrus.Logger) {
func (bi *BuildInfo) Log(logger logger.Service) {
logger.Infof("Version %s", bi.CloudflaredVersion)
logger.Infof("GOOS: %s, GOVersion: %s, GoArch: %s", bi.GoOS, bi.GoVersion, bi.GoArch)
}

View File

@@ -9,6 +9,7 @@ import (
homedir "github.com/mitchellh/go-homedir"
"gopkg.in/urfave/cli.v2"
"gopkg.in/urfave/cli.v2/altsrc"
"gopkg.in/yaml.v2"
)
var (
@@ -63,6 +64,35 @@ func FindDefaultConfigPath() string {
return ""
}
// FindLogSettings gets the log directory and level from the config file
func FindLogSettings() (string, string) {
configPath := FindDefaultConfigPath()
defaultDirectory := filepath.Dir(configPath)
defaultLevel := "info"
file, err := os.Open(configPath)
if err != nil {
return defaultDirectory, defaultLevel
}
defer file.Close()
var config Root
if err := yaml.NewDecoder(file).Decode(&config); err != nil {
return defaultDirectory, defaultLevel
}
directory := defaultDirectory
if config.LogDirectory != "" {
directory = config.LogDirectory
}
level := defaultLevel
if config.LogLevel != "" {
level = config.LogLevel
}
return directory, level
}
// ValidateUnixSocket ensures --unix-socket param is used exclusively
// i.e. it fails if a user specifies both --url and --unix-socket
func ValidateUnixSocket(c *cli.Context) (string, error) {

View File

@@ -4,9 +4,8 @@ import (
"errors"
"os"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/watcher"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)
@@ -27,12 +26,12 @@ type FileManager struct {
watcher watcher.Notifier
notifier Notifier
configPath string
logger *logrus.Logger
logger logger.Service
ReadConfig func(string) (Root, error)
}
// NewFileManager creates a config manager
func NewFileManager(watcher watcher.Notifier, configPath string, logger *logrus.Logger) (*FileManager, error) {
func NewFileManager(watcher watcher.Notifier, configPath string, logger logger.Service) (*FileManager, error) {
m := &FileManager{
watcher: watcher,
configPath: configPath,
@@ -94,7 +93,7 @@ func readConfigFromPath(configPath string) (Root, error) {
func (m *FileManager) WatcherItemDidChange(filepath string) {
config, err := m.GetConfig()
if err != nil {
m.logger.WithError(err).Error("Failed to read new config")
m.logger.Errorf("Failed to read new config: %s", err)
return
}
m.logger.Info("Config file has been updated")
@@ -103,5 +102,5 @@ func (m *FileManager) WatcherItemDidChange(filepath string) {
// WatcherDidError notifies of errors with the file watcher
func (m *FileManager) WatcherDidError(err error) {
m.logger.WithError(err).Error("Config watcher encountered an error")
m.logger.Errorf("Config watcher encountered an error: %s", err)
}

View File

@@ -4,7 +4,7 @@ import (
"os"
"testing"
"github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/watcher"
"github.com/stretchr/testify/assert"
)
@@ -65,7 +65,8 @@ func TestConfigChanged(t *testing.T) {
wait := make(chan struct{})
w := &mockFileWatcher{path: filePath, ready: wait}
logger := log.CreateLogger()
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
service, err := NewFileManager(w, filePath, logger)
service.ReadConfig = configRead
assert.NoError(t, err)

View File

@@ -23,20 +23,22 @@ type Tunnel struct {
// DNSResolver represents a client side DNS resolver
type DNSResolver struct {
Enabled bool `json:"enabled"`
Address string `json:"address"`
Port uint16 `json:"port"`
Upstreams []string `json:"upstreams"`
Bootstraps []string `json:"bootstraps"`
Address string `json:"address,omitempty"`
Port uint16 `json:"port,omitempty"`
Upstreams []string `json:"upstreams,omitempty"`
Bootstraps []string `json:"bootstraps,omitempty"`
}
// Root is the base options to configure the service
type Root struct {
OrgKey string `json:"org_key"`
OrgKey string `json:"org_key" yaml:"orgKey"`
ConfigType string `json:"type"`
CheckinInterval int `json:"checkin_interval"`
LogDirectory string `json:"log_directory" yaml:"logDirectory,omitempty"`
LogLevel string `json:"log_level" yaml:"logLevel"`
CheckinInterval int `json:"checkin_interval" yaml:"checkinInterval"`
Forwarders []Forwarder `json:"forwarders,omitempty"`
Tunnels []Tunnel `json:"tunnels,omitempty"`
Resolver DNSResolver `json:"resolver"`
Resolver DNSResolver `json:"resolver,omitempty"`
}
// Hash returns the computed values to see if the forwarder values change

View File

@@ -8,6 +8,8 @@ import (
"path/filepath"
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
"github.com/pkg/errors"
cli "gopkg.in/urfave/cli.v2"
)
@@ -178,7 +180,7 @@ func isSystemd() bool {
return false
}
func copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile string) error {
func copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile string, logger logger.Service) error {
if err := ensureConfigDirExists(serviceConfigDir); err != nil {
return err
}
@@ -192,10 +194,16 @@ func copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile str
if err := copyConfig(srcConfigPath, destConfigPath); err != nil {
return err
}
logger.Infof("Copied %s to %s", srcConfigPath, destConfigPath)
return nil
}
func installLinuxService(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
etPath, err := os.Executable()
if err != nil {
return fmt.Errorf("error determining executable path: %v", err)
@@ -205,8 +213,8 @@ func installLinuxService(c *cli.Context) error {
userConfigDir := filepath.Dir(c.String("config"))
userConfigFile := filepath.Base(c.String("config"))
userCredentialFile := config.DefaultCredentialFile
if err = copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile); err != nil {
logger.WithError(err).Infof("Failed to copy user configuration. Before running the service, ensure that %s contains two files, %s and %s",
if err = copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile, logger); err != nil {
logger.Errorf("Failed to copy user configuration: %s. Before running the service, ensure that %s contains two files, %s and %s", err,
serviceConfigDir, serviceCredentialFile, serviceConfigFile)
return err
}
@@ -214,41 +222,41 @@ func installLinuxService(c *cli.Context) error {
switch {
case isSystemd():
logger.Infof("Using Systemd")
return installSystemd(&templateArgs)
return installSystemd(&templateArgs, logger)
default:
logger.Infof("Using Sysv")
return installSysv(&templateArgs)
return installSysv(&templateArgs, logger)
}
}
func installSystemd(templateArgs *ServiceTemplateArgs) error {
func installSystemd(templateArgs *ServiceTemplateArgs, logger logger.Service) error {
for _, serviceTemplate := range systemdTemplates {
err := serviceTemplate.Generate(templateArgs)
if err != nil {
logger.WithError(err).Infof("error generating service template")
logger.Errorf("error generating service template: %s", err)
return err
}
}
if err := runCommand("systemctl", "enable", "cloudflared.service"); err != nil {
logger.WithError(err).Infof("systemctl enable cloudflared.service error")
logger.Errorf("systemctl enable cloudflared.service error: %s", err)
return err
}
if err := runCommand("systemctl", "start", "cloudflared-update.timer"); err != nil {
logger.WithError(err).Infof("systemctl start cloudflared-update.timer error")
logger.Errorf("systemctl start cloudflared-update.timer error: %s", err)
return err
}
logger.Infof("systemctl daemon-reload")
return runCommand("systemctl", "daemon-reload")
}
func installSysv(templateArgs *ServiceTemplateArgs) error {
func installSysv(templateArgs *ServiceTemplateArgs, logger logger.Service) error {
confPath, err := sysvTemplate.ResolvePath()
if err != nil {
logger.WithError(err).Infof("error resolving system path")
logger.Errorf("error resolving system path: %s", err)
return err
}
if err := sysvTemplate.Generate(templateArgs); err != nil {
logger.WithError(err).Infof("error generating system template")
logger.Errorf("error generating system template: %s", err)
return err
}
for _, i := range [...]string{"2", "3", "4", "5"} {
@@ -265,28 +273,33 @@ func installSysv(templateArgs *ServiceTemplateArgs) error {
}
func uninstallLinuxService(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
switch {
case isSystemd():
logger.Infof("Using Systemd")
return uninstallSystemd()
return uninstallSystemd(logger)
default:
logger.Infof("Using Sysv")
return uninstallSysv()
return uninstallSysv(logger)
}
}
func uninstallSystemd() error {
func uninstallSystemd(logger logger.Service) error {
if err := runCommand("systemctl", "disable", "cloudflared.service"); err != nil {
logger.WithError(err).Infof("systemctl disable cloudflared.service error")
logger.Errorf("systemctl disable cloudflared.service error: %s", err)
return err
}
if err := runCommand("systemctl", "stop", "cloudflared-update.timer"); err != nil {
logger.WithError(err).Infof("systemctl stop cloudflared-update.timer error")
logger.Errorf("systemctl stop cloudflared-update.timer error: %s", err)
return err
}
for _, serviceTemplate := range systemdTemplates {
if err := serviceTemplate.Remove(); err != nil {
logger.WithError(err).Infof("error removing service template")
logger.Errorf("error removing service template: %s", err)
return err
}
}
@@ -294,9 +307,9 @@ func uninstallSystemd() error {
return nil
}
func uninstallSysv() error {
func uninstallSysv(logger logger.Service) error {
if err := sysvTemplate.Remove(); err != nil {
logger.WithError(err).Infof("error removing service template")
logger.Errorf("error removing service template: %s", err)
return err
}
for _, i := range [...]string{"2", "3", "4", "5"} {

View File

@@ -8,6 +8,7 @@ import (
"gopkg.in/urfave/cli.v2"
"github.com/cloudflare/cloudflared/logger"
"github.com/pkg/errors"
)
@@ -105,6 +106,11 @@ func stderrPath() (string, error) {
}
func installLaunchd(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
if isRootUser() {
logger.Infof("Installing Argo Tunnel client as a system launch daemon. " +
"Argo Tunnel client will run at boot")
@@ -116,35 +122,38 @@ func installLaunchd(c *cli.Context) error {
}
etPath, err := os.Executable()
if err != nil {
logger.WithError(err).Errorf("Error determining executable path")
logger.Errorf("Error determining executable path: %s", err)
return fmt.Errorf("Error determining executable path: %v", err)
}
installPath, err := installPath()
if err != nil {
logger.Errorf("Error determining install path: %s", err)
return errors.Wrap(err, "Error determining install path")
}
stdoutPath, err := stdoutPath()
if err != nil {
logger.Errorf("error determining stdout path: %s", err)
return errors.Wrap(err, "error determining stdout path")
}
stderrPath, err := stderrPath()
if err != nil {
logger.Errorf("error determining stderr path: %s", err)
return errors.Wrap(err, "error determining stderr path")
}
launchdTemplate := newLaunchdTemplate(installPath, stdoutPath, stderrPath)
if err != nil {
logger.WithError(err).Errorf("error creating launchd template")
logger.Errorf("error creating launchd template: %s", err)
return errors.Wrap(err, "error creating launchd template")
}
templateArgs := ServiceTemplateArgs{Path: etPath}
err = launchdTemplate.Generate(&templateArgs)
if err != nil {
logger.WithError(err).Errorf("error generating launchd template")
logger.Errorf("error generating launchd template: %s", err)
return err
}
plistPath, err := launchdTemplate.ResolvePath()
if err != nil {
logger.WithError(err).Infof("error resolving launchd template path")
logger.Errorf("error resolving launchd template path: %s", err)
return err
}
@@ -153,6 +162,11 @@ func installLaunchd(c *cli.Context) error {
}
func uninstallLaunchd(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
if isRootUser() {
logger.Infof("Uninstalling Argo Tunnel as a system launch daemon")
} else {
@@ -176,12 +190,12 @@ func uninstallLaunchd(c *cli.Context) error {
}
plistPath, err := launchdTemplate.ResolvePath()
if err != nil {
logger.WithError(err).Infof("error resolving launchd template path")
logger.Errorf("error resolving launchd template path: %s", err)
return err
}
err = runCommand("launchctl", "unload", plistPath)
if err != nil {
logger.WithError(err).Infof("error unloading")
logger.Errorf("error unloading: %s", err)
return err
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/cmd/cloudflared/tunnel"
"github.com/cloudflare/cloudflared/cmd/cloudflared/updater"
"github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/metrics"
"github.com/cloudflare/cloudflared/overwatch"
"github.com/cloudflare/cloudflared/watcher"
@@ -28,7 +28,6 @@ const (
var (
Version = "DEV"
BuildTime = "unknown"
logger = log.CreateLogger()
// Mostly network errors that we don't want reported back to Sentry, this is done by substring match.
ignoredErrors = []string{
"connection reset by peer",
@@ -148,7 +147,6 @@ func userHomeDir() (string, error) {
// use with sudo.
homeDir, err := homedir.Dir()
if err != nil {
logger.WithError(err).Error("Cannot determine home directory for the user")
return "", errors.Wrap(err, "Cannot determine home directory for the user")
}
return homeDir, nil
@@ -167,17 +165,25 @@ func handleError(err error) {
// cloudflared was started without any flags
func handleServiceMode(shutdownC chan struct{}) error {
logDirectory, logLevel := config.FindLogSettings()
logger, err := logger.New(logger.DefaultFile(logDirectory), logger.LogLevelString(logLevel))
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
logger.Infof("logging to directory: %s", logDirectory)
// start the main run loop that reads from the config file
f, err := watcher.NewFile()
if err != nil {
logger.WithError(err).Error("Cannot load config file")
logger.Errorf("Cannot load config file: %s", err)
return err
}
configPath := config.FindDefaultConfigPath()
configManager, err := config.NewFileManager(f, configPath, logger)
if err != nil {
logger.WithError(err).Error("Cannot setup config file for monitoring")
logger.Errorf("Cannot setup config file for monitoring: %s", err)
return err
}
@@ -185,7 +191,7 @@ func handleServiceMode(shutdownC chan struct{}) error {
appService := NewAppService(configManager, serviceManager, shutdownC, logger)
if err := appService.Run(); err != nil {
logger.WithError(err).Error("Failed to start app service")
logger.Errorf("Failed to start app service: %s", err)
return err
}
return nil

View File

@@ -73,21 +73,16 @@ func runCommand(command string, args ...string) error {
cmd := exec.Command(command, args...)
stderr, err := cmd.StderrPipe()
if err != nil {
logger.WithError(err).Infof("error getting stderr pipe")
return fmt.Errorf("error getting stderr pipe: %v", err)
}
err = cmd.Start()
if err != nil {
logger.WithError(err).Infof("error starting %s", command)
return fmt.Errorf("error starting %s: %v", command, err)
}
commandErr, _ := ioutil.ReadAll(stderr)
if len(commandErr) > 0 {
logger.Errorf("%s: %s", command, commandErr)
}
ioutil.ReadAll(stderr)
err = cmd.Wait()
if err != nil {
logger.WithError(err).Infof("%s returned error", command)
return fmt.Errorf("%s returned with error: %v", command, err)
}
return nil
@@ -148,8 +143,7 @@ func copyConfig(srcConfigPath, destConfigPath string) error {
// Copy or create config
destFile, exists, err := openFile(destConfigPath, true)
if err != nil {
logger.WithError(err).Infof("cannot open %s", destConfigPath)
return err
return fmt.Errorf("cannot open %s with error: %s", destConfigPath, err)
} else if exists {
// config already exists, do nothing
return nil
@@ -173,7 +167,6 @@ func copyConfig(srcConfigPath, destConfigPath string) error {
if err != nil {
return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err)
}
logger.Infof("Copied %s to %s", srcConfigPath, destConfigPath)
}
return nil

View File

@@ -14,7 +14,7 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/cmd/cloudflared/path"
"github.com/cloudflare/cloudflared/cmd/cloudflared/transfer"
"github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/origin"
"github.com/coreos/go-oidc/jose"
)
@@ -23,8 +23,6 @@ const (
keyName = "token"
)
var logger = log.CreateLogger()
type lock struct {
lockFilePath string
backoff *origin.BackoffHandler
@@ -130,7 +128,7 @@ func isTokenLocked(lockFilePath string) bool {
}
// FetchToken will either load a stored token or generate a new one
func FetchToken(appURL *url.URL) (string, error) {
func FetchToken(appURL *url.URL, logger logger.Service) (string, error) {
if token, err := GetTokenIfExists(appURL); token != "" && err == nil {
return token, nil
}
@@ -156,7 +154,7 @@ func FetchToken(appURL *url.URL) (string, error) {
// this weird parameter is the resource name (token) and the key/value
// we want to send to the transfer service. the key is token and the value
// is blank (basically just the id generated in the transfer service)
token, err := transfer.Run(appURL, keyName, keyName, "", path, true)
token, err := transfer.Run(appURL, keyName, keyName, "", path, true, logger)
if err != nil {
return "", err
}

View File

@@ -14,7 +14,7 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/encrypter"
"github.com/cloudflare/cloudflared/cmd/cloudflared/shell"
"github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/logger"
)
const (
@@ -22,15 +22,13 @@ const (
clientTimeout = time.Second * 60
)
var logger = log.CreateLogger()
// Run does the transfer "dance" with the end result downloading the supported resource.
// The expanded description is run is encapsulation of shared business logic needed
// to request a resource (token/cert/etc) from the transfer service (loginhelper).
// The "dance" we refer to is building a HTTP request, opening that in a browser waiting for
// the user to complete an action, while it long polls in the background waiting for an
// action to be completed to download the resource.
func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncrypt bool) ([]byte, error) {
func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncrypt bool, logger logger.Service) ([]byte, error) {
encrypterClient, err := encrypter.New("cloudflared_priv.pem", "cloudflared_pub.pem")
if err != nil {
return nil, err
@@ -51,7 +49,7 @@ func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncr
var resourceData []byte
if shouldEncrypt {
buf, key, err := transferRequest(baseStoreURL + "transfer/" + encrypterClient.PublicKey())
buf, key, err := transferRequest(baseStoreURL+"transfer/"+encrypterClient.PublicKey(), logger)
if err != nil {
return nil, err
}
@@ -67,7 +65,7 @@ func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncr
resourceData = decrypted
} else {
buf, _, err := transferRequest(baseStoreURL + encrypterClient.PublicKey())
buf, _, err := transferRequest(baseStoreURL+encrypterClient.PublicKey(), logger)
if err != nil {
return nil, err
}
@@ -99,17 +97,17 @@ func buildRequestURL(baseURL *url.URL, key, value string, cli bool) (string, err
}
// transferRequest downloads the requested resource from the request URL
func transferRequest(requestURL string) ([]byte, string, error) {
func transferRequest(requestURL string, logger logger.Service) ([]byte, string, error) {
client := &http.Client{Timeout: clientTimeout}
const pollAttempts = 10
// we do "long polling" on the endpoint to get the resource.
for i := 0; i < pollAttempts; i++ {
buf, key, err := poll(client, requestURL)
buf, key, err := poll(client, requestURL, logger)
if err != nil {
return nil, "", err
} else if len(buf) > 0 {
if err := putSuccess(client, requestURL); err != nil {
logger.WithError(err).Error("Failed to update resource success")
logger.Errorf("Failed to update resource success: %s", err)
}
return buf, key, nil
}
@@ -118,7 +116,7 @@ func transferRequest(requestURL string) ([]byte, string, error) {
}
// poll the endpoint for the request resource, waiting for the user interaction
func poll(client *http.Client, requestURL string) ([]byte, string, error) {
func poll(client *http.Client, requestURL string, logger logger.Service) ([]byte, string, error) {
resp, err := client.Get(requestURL)
if err != nil {
return nil, "", err

View File

@@ -25,6 +25,7 @@ import (
"github.com/cloudflare/cloudflared/dbconnect"
"github.com/cloudflare/cloudflared/h2mux"
"github.com/cloudflare/cloudflared/hello"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/metrics"
"github.com/cloudflare/cloudflared/origin"
"github.com/cloudflare/cloudflared/signal"
@@ -93,6 +94,9 @@ const (
bastionFlag = "bastion"
noIntentMsg = "The --intent argument is required. Cloudflared looks up an Intent to determine what configuration to use (i.e. which tunnels to start). If you don't have any Intents yet, you can use a placeholder Intent Label for now. Then, when you make an Intent with that label, cloudflared will get notified and open the tunnels you specified in that Intent."
debugLevelWarning = "At debug level, request URL, method, protocol, content legnth and header will be logged. " +
"Response status, content length and header will also be logged in debug level."
)
var (
@@ -212,7 +216,28 @@ func Init(v string, s, g chan struct{}) {
version, shutdownC, graceShutdownC = v, s, g
}
func createLogger(c *cli.Context, isTransport bool) (logger.Service, error) {
loggerOpts := []logger.Option{}
logPath := c.String("logfile")
if logPath != "" {
loggerOpts = append(loggerOpts, logger.DefaultFile(logPath))
}
logLevel := c.String("loglevel")
if isTransport {
logLevel = c.String("transport-loglevel")
}
loggerOpts = append(loggerOpts, logger.LogLevelString(logLevel))
return logger.New(loggerOpts...)
}
func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan struct{}) error {
logger, err := createLogger(c, false)
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
_ = raven.SetDSN(sentryDSN)
var wg sync.WaitGroup
listeners := gracenet.Net{}
@@ -221,64 +246,45 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
dnsReadySignal := make(chan struct{})
if c.String("config") == "" {
logger.Warnf("Cannot determine default configuration path. No file %v in %v", config.DefaultConfigFiles, config.DefaultConfigDirs)
}
if err := configMainLogger(c); err != nil {
return errors.Wrap(err, "Error configuring logger")
}
transportLogger, err := configTransportLogger(c)
if err != nil {
return errors.Wrap(err, "Error configuring transport logger")
logger.Infof("Cannot determine default configuration path. No file %v in %v", config.DefaultConfigFiles, config.DefaultConfigDirs)
}
if c.IsSet("trace-output") {
tmpTraceFile, err := ioutil.TempFile("", "trace")
if err != nil {
logger.WithError(err).Error("Failed to create new temporary file to save trace output")
logger.Errorf("Failed to create new temporary file to save trace output: %s", err)
}
defer func() {
if err := tmpTraceFile.Close(); err != nil {
logger.WithError(err).Errorf("Failed to close trace output file %s", tmpTraceFile.Name())
logger.Errorf("Failed to close trace output file %s with error: %s", tmpTraceFile.Name(), err)
}
if err := os.Rename(tmpTraceFile.Name(), c.String("trace-output")); err != nil {
logger.WithError(err).Errorf("Failed to rename temporary trace output file %s to %s", tmpTraceFile.Name(), c.String("trace-output"))
logger.Errorf("Failed to rename temporary trace output file %s to %s with error: %s", tmpTraceFile.Name(), c.String("trace-output"), err)
} else {
err := os.Remove(tmpTraceFile.Name())
if err != nil {
logger.WithError(err).Errorf("Failed to remove the temporary trace file %s", tmpTraceFile.Name())
logger.Errorf("Failed to remove the temporary trace file %s with error: %s", tmpTraceFile.Name(), err)
}
}
}()
if err := trace.Start(tmpTraceFile); err != nil {
logger.WithError(err).Error("Failed to start trace")
logger.Errorf("Failed to start trace: %s", err)
return errors.Wrap(err, "Error starting tracing")
}
defer trace.Stop()
}
if c.String("logfile") != "" {
if err := initLogFile(c, logger, transportLogger); err != nil {
logger.Error(err)
}
}
if err := handleDeprecatedOptions(c); err != nil {
return err
}
buildInfo := buildinfo.GetBuildInfo(version)
buildInfo.Log(logger)
logClientOptions(c)
logClientOptions(c, logger)
if c.IsSet("proxy-dns") {
wg.Add(1)
go func() {
defer wg.Done()
errC <- runDNSProxyServer(c, dnsReadySignal, shutdownC)
errC <- runDNSProxyServer(c, dnsReadySignal, shutdownC, logger)
}()
} else {
close(dnsReadySignal)
@@ -289,7 +295,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
metricsListener, err := listeners.Listen("tcp", c.String("metrics"))
if err != nil {
logger.WithError(err).Error("Error opening metrics server listener")
logger.Errorf("Error opening metrics server listener: %s", err)
return errors.Wrap(err, "Error opening metrics server listener")
}
defer metricsListener.Close()
@@ -301,12 +307,12 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
go notifySystemd(connectedSignal)
if c.IsSet("pidfile") {
go writePidFile(connectedSignal, c.String("pidfile"))
go writePidFile(connectedSignal, c.String("pidfile"), logger)
}
cloudflaredID, err := uuid.NewRandom()
if err != nil {
logger.WithError(err).Error("Cannot generate cloudflared ID")
logger.Errorf("Cannot generate cloudflared ID: %s", err)
return err
}
@@ -317,16 +323,16 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
}()
if c.IsSet("use-declarative-tunnels") {
return startDeclarativeTunnel(ctx, c, cloudflaredID, buildInfo, &listeners)
return startDeclarativeTunnel(ctx, c, cloudflaredID, buildInfo, &listeners, logger)
}
// update needs to be after DNS proxy is up to resolve equinox server address
if updater.IsAutoupdateEnabled(c) {
if updater.IsAutoupdateEnabled(c, logger) {
logger.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
wg.Add(1)
go func() {
defer wg.Done()
autoupdater := updater.NewAutoUpdater(c.Duration("autoupdate-freq"), &listeners)
autoupdater := updater.NewAutoUpdater(c.Duration("autoupdate-freq"), &listeners, logger)
errC <- autoupdater.Run(ctx)
}()
}
@@ -335,14 +341,14 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
if dnsProxyStandAlone(c) {
connectedSignal.Notify()
// no grace period, handle SIGINT/SIGTERM immediately
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, 0)
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, 0, logger)
}
if c.IsSet("hello-world") {
logger.Infof("hello-world set")
helloListener, err := hello.CreateTLSListener("127.0.0.1:")
if err != nil {
logger.WithError(err).Error("Cannot start Hello World Server")
logger.Errorf("Cannot start Hello World Server: %s", err)
return errors.Wrap(err, "Cannot start Hello World Server")
}
defer helloListener.Close()
@@ -369,13 +375,13 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
c.String(accessKeyIDFlag), c.String(secretIDFlag), c.String(sessionTokenIDFlag), c.String(s3URLFlag))
if err != nil {
msg := "Cannot create uploader for SSH Server"
logger.WithError(err).Error(msg)
logger.Errorf("%s: %s", msg, err)
return errors.Wrap(err, msg)
}
if err := os.MkdirAll(sshLogFileDirectory, 0700); err != nil {
msg := fmt.Sprintf("Cannot create SSH log file directory %s", sshLogFileDirectory)
logger.WithError(err).Errorf(msg)
logger.Errorf("%s: %s", msg, err)
return errors.Wrap(err, msg)
}
@@ -389,14 +395,14 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
server, err := sshserver.New(logManager, logger, version, localServerAddress, c.String("hostname"), c.Path(hostKeyPath), shutdownC, c.Duration(sshIdleTimeoutFlag), c.Duration(sshMaxTimeoutFlag))
if err != nil {
msg := "Cannot create new SSH Server"
logger.WithError(err).Error(msg)
logger.Errorf("%s: %s", msg, err)
return errors.Wrap(err, msg)
}
wg.Add(1)
go func() {
defer wg.Done()
if err = server.Start(); err != nil && err != ssh.ErrServerClosed {
logger.WithError(err).Error("SSH server error")
logger.Errorf("SSH server error: %s", err)
// TODO: remove when declarative tunnels are implemented.
close(shutdownC)
}
@@ -407,7 +413,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
if staticHost := hostnameFromURI(c.String("url")); isProxyDestinationConfigured(staticHost, c) {
listener, err := net.Listen("tcp", "127.0.0.1:")
if err != nil {
logger.WithError(err).Error("Cannot start Websocket Proxy Server")
logger.Errorf("Cannot start Websocket Proxy Server: %s", err)
return errors.Wrap(err, "Cannot start Websocket Proxy Server")
}
wg.Add(1)
@@ -428,7 +434,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
if finalDestination := requestHeaders.Get(h2mux.CFJumpDestinationHeader); finalDestination != "" {
token := requestHeaders.Get(h2mux.CFAccessTokenHeader)
if err := websocket.SendSSHPreamble(remoteConn, finalDestination, token); err != nil {
logger.WithError(err).Error("Failed to send SSH preamble")
logger.Errorf("Failed to send SSH preamble: %s", err)
return
}
}
@@ -440,6 +446,11 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
c.Set("url", "http://"+listener.Addr().String())
}
transportLogger, err := createLogger(c, true)
if err != nil {
return errors.Wrap(err, "error setting up transport logger")
}
tunnelConfig, err := prepareTunnelConfig(c, buildInfo, version, logger, transportLogger)
if err != nil {
return err
@@ -447,8 +458,8 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
reconnectCh := make(chan origin.ReconnectSignal, 1)
if c.IsSet("stdin-control") {
logger.Warn("Enabling control through stdin")
go stdinControl(reconnectCh)
logger.Info("Enabling control through stdin")
go stdinControl(reconnectCh, logger)
}
wg.Add(1)
@@ -456,21 +467,27 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
defer wg.Done()
errC <- origin.StartTunnelDaemon(ctx, tunnelConfig, connectedSignal, cloudflaredID, reconnectCh)
}()
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"))
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"), logger)
}
func Before(c *cli.Context) error {
logger, err := createLogger(c, false)
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
if c.String("config") == "" {
logger.Debugf("Cannot determine default configuration path. No file %v in %v", config.DefaultConfigFiles, config.DefaultConfigDirs)
}
inputSource, err := config.FindInputSourceContext(c)
if err != nil {
logger.WithError(err).Errorf("Cannot load configuration from %s", c.String("config"))
logger.Errorf("Cannot load configuration from %s: %s", c.String("config"), err)
return err
} else if inputSource != nil {
err := altsrc.ApplyInputSourceValues(c, inputSource, c.App.Flags)
if err != nil {
logger.WithError(err).Errorf("Cannot apply configuration from %s", c.String("config"))
logger.Errorf("Cannot apply configuration from %s: %s", c.String("config"), err)
return err
}
logger.Debugf("Applied configuration from %s", c.String("config"))
@@ -488,10 +505,11 @@ func startDeclarativeTunnel(ctx context.Context,
cloudflaredID uuid.UUID,
buildInfo *buildinfo.BuildInfo,
listeners *gracenet.Net,
logger logger.Service,
) error {
reverseProxyOrigin, err := defaultOriginConfig(c)
if err != nil {
logger.WithError(err)
logger.Errorf("%s", err)
return err
}
reverseProxyConfig, err := pogs.NewReverseProxyConfig(
@@ -502,7 +520,7 @@ func startDeclarativeTunnel(ctx context.Context,
c.Uint64("compression-quality"),
)
if err != nil {
logger.WithError(err).Error("Cannot initialize default client config because reverse proxy config is invalid")
logger.Errorf("Cannot initialize default client config because reverse proxy config is invalid: %s", err)
return err
}
defaultClientConfig := &pogs.ClientConfig{
@@ -522,22 +540,22 @@ func startDeclarativeTunnel(ctx context.Context,
ReverseProxyConfigs: []*pogs.ReverseProxyConfig{reverseProxyConfig},
}
autoupdater := updater.NewAutoUpdater(defaultClientConfig.SupervisorConfig.AutoUpdateFrequency, listeners)
autoupdater := updater.NewAutoUpdater(defaultClientConfig.SupervisorConfig.AutoUpdateFrequency, listeners, logger)
originCert, err := getOriginCert(c)
originCert, err := getOriginCert(c, logger)
if err != nil {
logger.WithError(err).Error("error getting origin cert")
logger.Errorf("error getting origin cert: %s", err)
return err
}
toEdgeTLSConfig, err := tlsconfig.CreateTunnelConfig(c)
if err != nil {
logger.WithError(err).Error("unable to create TLS config to connect with edge")
logger.Errorf("unable to create TLS config to connect with edge: %s", err)
return err
}
tags, err := NewTagSliceFromCLI(c.StringSlice("tag"))
if err != nil {
logger.WithError(err).Error("unable to parse tag")
logger.Errorf("unable to parse tag: %s", err)
return err
}
@@ -556,13 +574,13 @@ func startDeclarativeTunnel(ctx context.Context,
serviceDiscoverer, err := serviceDiscoverer(c, logger)
if err != nil {
logger.WithError(err).Error("unable to create service discoverer")
logger.Errorf("unable to create service discoverer: %s", err)
return err
}
supervisor, err := supervisor.NewSupervisor(defaultClientConfig, originCert, toEdgeTLSConfig,
serviceDiscoverer, cloudflaredConfig, autoupdater, updater.SupportAutoUpdate(), logger)
serviceDiscoverer, cloudflaredConfig, autoupdater, updater.SupportAutoUpdate(logger), logger)
if err != nil {
logger.WithError(err).Error("unable to create Supervisor")
logger.Errorf("unable to create Supervisor: %s", err)
return err
}
return supervisor.Run(ctx)
@@ -604,17 +622,18 @@ func waitToShutdown(wg *sync.WaitGroup,
errC chan error,
shutdownC, graceShutdownC chan struct{},
gracePeriod time.Duration,
logger logger.Service,
) error {
var err error
if gracePeriod > 0 {
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceShutdownC, gracePeriod)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceShutdownC, gracePeriod, logger)
} else {
err = waitForSignal(errC, shutdownC)
err = waitForSignal(errC, shutdownC, logger)
close(graceShutdownC)
}
if err != nil {
logger.WithError(err).Error("Quitting due to error")
logger.Errorf("Quitting due to error: %s", err)
} else {
logger.Info("Quitting...")
}
@@ -632,16 +651,16 @@ func notifySystemd(waitForSignal *signal.Signal) {
daemon.SdNotify(false, "READY=1")
}
func writePidFile(waitForSignal *signal.Signal, pidFile string) {
func writePidFile(waitForSignal *signal.Signal, pidFile string, logger logger.Service) {
<-waitForSignal.Wait()
expandedPath, err := homedir.Expand(pidFile)
if err != nil {
logger.WithError(err).Errorf("Unable to expand %s, try to use absolute path in --pidfile", pidFile)
logger.Errorf("Unable to expand %s, try to use absolute path in --pidfile: %s", pidFile, err)
return
}
file, err := os.Create(expandedPath)
if err != nil {
logger.WithError(err).Errorf("Unable to write pid to %s", expandedPath)
logger.Errorf("Unable to write pid to %s: %s", expandedPath, err)
return
}
defer file.Close()
@@ -888,15 +907,15 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
altsrc.NewStringFlag(&cli.StringFlag{
Name: "loglevel",
Value: "info",
Usage: "Application logging level {panic, fatal, error, warn, info, debug}. " + debugLevelWarning,
Usage: "Application logging level {fatal, error, info, debug}. " + debugLevelWarning,
EnvVars: []string{"TUNNEL_LOGLEVEL"},
Hidden: shouldHide,
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "transport-loglevel",
Aliases: []string{"proto-loglevel"}, // This flag used to be called proto-loglevel
Value: "warn",
Usage: "Transport logging level(previously called protocol logging level) {panic, fatal, error, warn, info, debug}",
Value: "fatal",
Usage: "Transport logging level(previously called protocol logging level) {fatal, error, info, debug}",
EnvVars: []string{"TUNNEL_PROTO_LOGLEVEL", "TUNNEL_TRANSPORT_LOGLEVEL"},
Hidden: shouldHide,
}),
@@ -1163,7 +1182,7 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
}
}
func stdinControl(reconnectCh chan origin.ReconnectSignal) {
func stdinControl(reconnectCh chan origin.ReconnectSignal, logger logger.Service) {
for {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
@@ -1185,7 +1204,7 @@ func stdinControl(reconnectCh chan origin.ReconnectSignal) {
logger.Infof("Sending reconnect signal %+v", reconnect)
reconnectCh <- reconnect
default:
logger.Warn("Unknown command: ", command)
logger.Infof("Unknown command: %s", command)
fallthrough
case "help":
logger.Info(`Supported command:

View File

@@ -15,6 +15,7 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/edgediscovery"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/origin"
"github.com/cloudflare/cloudflared/tlsconfig"
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
@@ -23,7 +24,6 @@ import (
"github.com/google/uuid"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
"gopkg.in/urfave/cli.v2"
)
@@ -47,25 +47,16 @@ func findDefaultOriginCertPath() string {
return ""
}
func generateRandomClientID(logger *logrus.Logger) (string, error) {
func generateRandomClientID(logger logger.Service) (string, error) {
u, err := uuid.NewRandom()
if err != nil {
logger.WithError(err).Error("couldn't create UUID for client ID")
logger.Errorf("couldn't create UUID for client ID %s", err)
return "", err
}
return u.String(), nil
}
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.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
}
func logClientOptions(c *cli.Context) {
func logClientOptions(c *cli.Context, logger logger.Service) {
flags := make(map[string]interface{})
for _, flag := range c.LocalFlagNames() {
flags[flag] = c.Generic(flag)
@@ -79,7 +70,7 @@ func logClientOptions(c *cli.Context) {
}
if len(flags) > 0 {
logger.WithFields(flags).Info("Flags")
logger.Infof("Environment variables %v", flags)
}
envs := make(map[string]string)
@@ -102,10 +93,10 @@ func dnsProxyStandAlone(c *cli.Context) bool {
return c.IsSet("proxy-dns") && (!c.IsSet("hostname") && !c.IsSet("tag") && !c.IsSet("hello-world"))
}
func findOriginCert(c *cli.Context) (string, error) {
func findOriginCert(c *cli.Context, logger logger.Service) (string, error) {
originCertPath := c.String("origincert")
if originCertPath == "" {
logger.Warnf("Cannot determine default origin certificate path. No file %s in %v", config.DefaultCredentialFile, config.DefaultConfigDirs)
logger.Infof("Cannot determine default origin certificate path. No file %s in %v", config.DefaultCredentialFile, config.DefaultConfigDirs)
if isRunningFromTerminal() {
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 "", fmt.Errorf("Client didn't specify origincert path when running from terminal")
@@ -117,7 +108,7 @@ func findOriginCert(c *cli.Context) (string, error) {
var err error
originCertPath, err = homedir.Expand(originCertPath)
if err != nil {
logger.WithError(err).Errorf("Cannot resolve path %s", originCertPath)
logger.Errorf("Cannot resolve path %s: %s", originCertPath, err)
return "", fmt.Errorf("Cannot resolve path %s", originCertPath)
}
// Check that the user has acquired a certificate using the login command
@@ -142,35 +133,36 @@ If you don't have a certificate signed by Cloudflare, run the command:
return originCertPath, nil
}
func readOriginCert(originCertPath string) ([]byte, error) {
func readOriginCert(originCertPath string, logger logger.Service) ([]byte, error) {
logger.Debugf("Reading origin cert from %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).Errorf("Cannot read %s to load origin certificate", originCertPath)
logger.Errorf("Cannot read %s to load origin certificate: %s", originCertPath, err)
return nil, fmt.Errorf("Cannot read %s to load origin certificate", originCertPath)
}
return originCert, nil
}
func getOriginCert(c *cli.Context) ([]byte, error) {
if originCertPath, err := findOriginCert(c); err != nil {
func getOriginCert(c *cli.Context, logger logger.Service) ([]byte, error) {
if originCertPath, err := findOriginCert(c, logger); err != nil {
return nil, err
} else {
return readOriginCert(originCertPath)
return readOriginCert(originCertPath, logger)
}
}
func prepareTunnelConfig(
c *cli.Context,
buildInfo *buildinfo.BuildInfo,
version string, logger,
transportLogger *logrus.Logger,
version string,
logger logger.Service,
transportLogger logger.Service,
) (*origin.TunnelConfig, error) {
hostname, err := validation.ValidateHostname(c.String("hostname"))
if err != nil {
logger.WithError(err).Error("Invalid hostname")
logger.Errorf("Invalid hostname: %s", err)
return nil, errors.Wrap(err, "Invalid hostname")
}
isFreeTunnel := hostname == ""
@@ -184,7 +176,7 @@ func prepareTunnelConfig(
tags, err := NewTagSliceFromCLI(c.StringSlice("tag"))
if err != nil {
logger.WithError(err).Error("Tag parse failure")
logger.Errorf("Tag parse failure: %s", err)
return nil, errors.Wrap(err, "Tag parse failure")
}
@@ -192,13 +184,13 @@ func prepareTunnelConfig(
originURL, err := config.ValidateUrl(c)
if err != nil {
logger.WithError(err).Error("Error validating origin URL")
logger.Errorf("Error validating origin URL: %s", err)
return nil, errors.Wrap(err, "Error validating origin URL")
}
var originCert []byte
if !isFreeTunnel {
originCert, err = getOriginCert(c)
originCert, err = getOriginCert(c, logger)
if err != nil {
return nil, errors.Wrap(err, "Error getting origin cert")
}
@@ -206,7 +198,7 @@ func prepareTunnelConfig(
originCertPool, err := tlsconfig.LoadOriginCA(c, logger)
if err != nil {
logger.WithError(err).Error("Error loading cert pool")
logger.Errorf("Error loading cert pool: %s", err)
return nil, errors.Wrap(err, "Error loading cert pool")
}
@@ -233,7 +225,7 @@ func prepareTunnelConfig(
if c.IsSet("unix-socket") {
unixSocket, err := config.ValidateUnixSocket(c)
if err != nil {
logger.WithError(err).Error("Error validating --unix-socket")
logger.Errorf("Error validating --unix-socket: %s", err)
return nil, errors.Wrap(err, "Error validating --unix-socket")
}
@@ -253,13 +245,13 @@ func prepareTunnelConfig(
// If tunnel running in bastion mode, a connection to origin will not exist until initiated by the client.
if !c.IsSet(bastionFlag) {
if err = validation.ValidateHTTPService(originURL, hostname, httpTransport); err != nil {
logger.WithError(err).Error("unable to connect to the origin")
logger.Errorf("unable to connect to the origin: %s", err)
}
}
toEdgeTLSConfig, err := tlsconfig.CreateTunnelConfig(c)
if err != nil {
logger.WithError(err).Error("unable to create TLS config to connect with edge")
logger.Errorf("unable to create TLS config to connect with edge: %s", err)
return nil, errors.Wrap(err, "unable to create TLS config to connect with edge")
}
@@ -280,6 +272,7 @@ func prepareTunnelConfig(
IsFreeTunnel: isFreeTunnel,
LBPool: c.String("lb-pool"),
Logger: logger,
TransportLogger: transportLogger,
MaxHeartbeats: c.Uint64("heartbeat-count"),
Metrics: tunnelMetrics,
MetricsUpdateFreq: c.Duration("metrics-update-freq"),
@@ -291,14 +284,13 @@ func prepareTunnelConfig(
RunFromTerminal: isRunningFromTerminal(),
Tags: tags,
TlsConfig: toEdgeTLSConfig,
TransportLogger: transportLogger,
UseDeclarativeTunnel: c.Bool("use-declarative-tunnels"),
UseReconnectToken: c.Bool("use-reconnect-token"),
UseQuickReconnects: c.Bool("use-quick-reconnects"),
}, nil
}
func serviceDiscoverer(c *cli.Context, logger *logrus.Logger) (*edgediscovery.Edge, error) {
func serviceDiscoverer(c *cli.Context, logger logger.Service) (*edgediscovery.Edge, error) {
// If --edge is specfied, resolve edge server addresses
if len(c.StringSlice("edge")) > 0 {
return edgediscovery.StaticEdge(logger, c.StringSlice("edge"))

View File

@@ -1,75 +0,0 @@
package tunnel
import (
"fmt"
"os"
"github.com/cloudflare/cloudflared/log"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"gopkg.in/urfave/cli.v2"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
)
const debugLevelWarning = "At debug level, request URL, method, protocol, content legnth and header will be logged. " +
"Response status, content length and header will also be logged in debug level."
var logger = log.CreateLogger()
func configMainLogger(c *cli.Context) error {
logLevel, err := logrus.ParseLevel(c.String("loglevel"))
if err != nil {
logger.WithError(err).Error("Unknown logging level specified")
return errors.Wrap(err, "Unknown logging level specified")
}
logger.SetLevel(logLevel)
if logLevel == logrus.DebugLevel {
logger.Warn(debugLevelWarning)
}
return nil
}
func configTransportLogger(c *cli.Context) (*logrus.Logger, error) {
transportLogLevel, err := logrus.ParseLevel(c.String("transport-loglevel"))
if err != nil {
logger.WithError(err).Fatal("Unknown transport logging level specified")
return nil, errors.Wrap(err, "Unknown transport logging level specified")
}
transportLogger := logrus.New()
transportLogger.Level = transportLogLevel
return transportLogger, nil
}
func initLogFile(c *cli.Context, loggers ...*logrus.Logger) error {
filePath, err := homedir.Expand(c.String("logfile"))
if err != nil {
return errors.Wrap(err, "Cannot resolve logfile path")
}
fileMode := os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC
// do not truncate log file if the client has been autoupdated
if c.Bool("is-autoupdated") {
fileMode = os.O_WRONLY | os.O_APPEND | os.O_CREATE
}
f, err := os.OpenFile(filePath, fileMode, 0664)
if err != nil {
errors.Wrap(err, fmt.Sprintf("Cannot open file %s", filePath))
}
defer f.Close()
pathMap := lfshook.PathMap{
logrus.DebugLevel: filePath,
logrus.WarnLevel: filePath,
logrus.InfoLevel: filePath,
logrus.ErrorLevel: filePath,
logrus.FatalLevel: filePath,
logrus.PanicLevel: filePath,
}
for _, l := range loggers {
l.Hooks.Add(lfshook.NewHook(pathMap, &logrus.JSONFormatter{}))
}
return nil
}

View File

@@ -9,7 +9,9 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/cmd/cloudflared/transfer"
"github.com/cloudflare/cloudflared/logger"
homedir "github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
cli "gopkg.in/urfave/cli.v2"
)
@@ -19,6 +21,11 @@ const (
)
func login(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
path, ok, err := checkForExistingCert()
if ok {
fmt.Fprintf(os.Stdout, "You have an existing certificate at %s which login would overwrite.\nIf this is intentional, please move or delete that file then run this command again.\n", path)
@@ -33,7 +40,7 @@ func login(c *cli.Context) error {
return err
}
_, err = transfer.Run(loginURL, "cert", "callback", callbackStoreURL, path, false)
_, err = transfer.Run(loginURL, "cert", "callback", callbackStoreURL, path, false, logger)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write the certificate due to the following error:\n%v\n\nYour browser will download the certificate instead. You will have to manually\ncopy it to the following path:\n\n%s\n", err, path)
return err

View File

@@ -1,6 +1,7 @@
package tunnel
import (
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/tunneldns"
"gopkg.in/urfave/cli.v2"
@@ -8,23 +9,20 @@ import (
"github.com/pkg/errors"
)
func runDNSProxyServer(c *cli.Context, dnsReadySignal, shutdownC chan struct{}) error {
func runDNSProxyServer(c *cli.Context, dnsReadySignal, shutdownC chan struct{}, logger logger.Service) error {
port := c.Int("proxy-dns-port")
if port <= 0 || port > 65535 {
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"), c.StringSlice("proxy-dns-bootstrap"))
listener, err := tunneldns.CreateListener(c.String("proxy-dns-address"), uint16(port), c.StringSlice("proxy-dns-upstream"), c.StringSlice("proxy-dns-bootstrap"), logger)
if err != nil {
close(dnsReadySignal)
listener.Stop()
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).Error("Cannot start the DNS over HTTPS proxy server")
return errors.Wrap(err, "Cannot start the DNS over HTTPS proxy server")
}
<-shutdownC

View File

@@ -5,12 +5,14 @@ import (
"os/signal"
"syscall"
"time"
"github.com/cloudflare/cloudflared/logger"
)
// waitForSignal notifies all routines to shutdownC immediately by closing the
// shutdownC when one of the routines in main exits, or when this process receives
// SIGTERM/SIGINT
func waitForSignal(errC chan error, shutdownC chan struct{}) error {
func waitForSignal(errC chan error, shutdownC chan struct{}, logger logger.Service) error {
signals := make(chan os.Signal, 10)
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
defer signal.Stop(signals)
@@ -39,6 +41,7 @@ func waitForSignal(errC chan error, shutdownC chan struct{}) error {
func waitForSignalWithGraceShutdown(errC chan error,
shutdownC, graceShutdownC chan struct{},
gracePeriod time.Duration,
logger logger.Service,
) error {
signals := make(chan os.Signal, 10)
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
@@ -53,9 +56,9 @@ func waitForSignalWithGraceShutdown(errC chan error,
case s := <-signals:
logger.Infof("Initiating graceful shutdown due to signal %s ...", s)
close(graceShutdownC)
waitForGracePeriod(signals, errC, shutdownC, gracePeriod)
waitForGracePeriod(signals, errC, shutdownC, gracePeriod, logger)
case <-graceShutdownC:
waitForGracePeriod(signals, errC, shutdownC, gracePeriod)
waitForGracePeriod(signals, errC, shutdownC, gracePeriod, logger)
case <-shutdownC:
close(graceShutdownC)
}
@@ -67,6 +70,7 @@ func waitForGracePeriod(signals chan os.Signal,
errC chan error,
shutdownC chan struct{},
gracePeriod time.Duration,
logger logger.Service,
) {
// Unregister signal handler early, so the client can send a second SIGTERM/SIGINT
// to force shutdown cloudflared

View File

@@ -6,6 +6,7 @@ import (
"testing"
"time"
"github.com/cloudflare/cloudflared/logger"
"github.com/stretchr/testify/assert"
)
@@ -27,6 +28,8 @@ func testChannelClosed(t *testing.T, c chan struct{}) {
}
func TestWaitForSignal(t *testing.T) {
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
// Test handling server error
errC := make(chan error)
shutdownC := make(chan struct{})
@@ -36,7 +39,7 @@ func TestWaitForSignal(t *testing.T) {
}()
// received error, shutdownC should be closed
err := waitForSignal(errC, shutdownC)
err := waitForSignal(errC, shutdownC, logger)
assert.Equal(t, serverErr, err)
testChannelClosed(t, shutdownC)
@@ -56,7 +59,7 @@ func TestWaitForSignal(t *testing.T) {
syscall.Kill(syscall.Getpid(), sig)
}(sig)
err = waitForSignal(errC, shutdownC)
err = waitForSignal(errC, shutdownC, logger)
assert.Equal(t, nil, err)
assert.Equal(t, shutdownErr, <-errC)
testChannelClosed(t, shutdownC)
@@ -73,8 +76,10 @@ func TestWaitForSignalWithGraceShutdown(t *testing.T) {
errC <- serverErr
}()
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
// received error, both shutdownC and graceshutdownC should be closed
err := waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick)
err := waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick, logger)
assert.Equal(t, serverErr, err)
testChannelClosed(t, shutdownC)
testChannelClosed(t, graceshutdownC)
@@ -84,7 +89,7 @@ func TestWaitForSignalWithGraceShutdown(t *testing.T) {
shutdownC = make(chan struct{})
graceshutdownC = make(chan struct{})
close(shutdownC)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick, logger)
assert.NoError(t, err)
testChannelClosed(t, shutdownC)
testChannelClosed(t, graceshutdownC)
@@ -94,7 +99,7 @@ func TestWaitForSignalWithGraceShutdown(t *testing.T) {
shutdownC = make(chan struct{})
graceshutdownC = make(chan struct{})
close(graceshutdownC)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick, logger)
assert.NoError(t, err)
testChannelClosed(t, shutdownC)
testChannelClosed(t, graceshutdownC)
@@ -117,7 +122,7 @@ func TestWaitForSignalWithGraceShutdown(t *testing.T) {
syscall.Kill(syscall.Getpid(), sig)
}(sig)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick, logger)
assert.Equal(t, nil, err)
assert.Equal(t, graceShutdownErr, <-errC)
testChannelClosed(t, shutdownC)
@@ -143,7 +148,7 @@ func TestWaitForSignalWithGraceShutdown(t *testing.T) {
syscall.Kill(syscall.Getpid(), sig)
}(sig)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick)
err = waitForSignalWithGraceShutdown(errC, shutdownC, graceshutdownC, tick, logger)
assert.Equal(t, nil, err)
assert.Equal(t, shutdownErr, <-errC)
testChannelClosed(t, shutdownC)

View File

@@ -12,14 +12,15 @@ import (
"github.com/cloudflare/cloudflared/certutil"
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/tunnelstore"
)
var (
outputFormatFlag = &cli.StringFlag{
Name: "output",
Name: "output",
Aliases: []string{"o"},
Usage: "Render output using given `FORMAT`. Valid options are 'json' or 'yaml'",
Usage: "Render output using given `FORMAT`. Valid options are 'json' or 'yaml'",
}
)
@@ -42,7 +43,12 @@ func createTunnel(c *cli.Context) error {
}
name := c.Args().First()
client, err := newTunnelstoreClient(c)
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
client, err := newTunnelstoreClient(c, logger)
if err != nil {
return err
}
@@ -72,7 +78,12 @@ func buildListCommand() *cli.Command {
}
func listTunnels(c *cli.Context) error {
client, err := newTunnelstoreClient(c)
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
client, err := newTunnelstoreClient(c, logger)
if err != nil {
return err
}
@@ -114,7 +125,12 @@ func deleteTunnel(c *cli.Context) error {
}
id := c.Args().First()
client, err := newTunnelstoreClient(c)
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
client, err := newTunnelstoreClient(c, logger)
if err != nil {
return err
}
@@ -139,13 +155,13 @@ func renderOutput(format string, v interface{}) error {
}
}
func newTunnelstoreClient(c *cli.Context) (tunnelstore.Client, error) {
originCertPath, err := findOriginCert(c)
func newTunnelstoreClient(c *cli.Context, logger logger.Service) (tunnelstore.Client, error) {
originCertPath, err := findOriginCert(c, logger)
if err != nil {
return nil, errors.Wrap(err, "Error locating origin cert")
}
blocks, err := readOriginCert(originCertPath)
blocks, err := readOriginCert(originCertPath, logger)
if err != nil {
return nil, errors.Wrapf(err, "Can't read origin cert from %s", originCertPath)
}
@@ -159,7 +175,7 @@ func newTunnelstoreClient(c *cli.Context) (tunnelstore.Client, error) {
return nil, errors.Errorf(`Origin certificate needs to be refreshed before creating new tunnels.\nDelete %s and run "cloudflared login" to obtain a new cert.`, originCertPath)
}
client := tunnelstore.NewRESTClient(c.String("api-url"), cert.AccountID, cert.ServiceKey)
client := tunnelstore.NewRESTClient(c.String("api-url"), cert.AccountID, cert.ServiceKey, logger)
return client, nil
}

View File

@@ -10,9 +10,10 @@ import (
"golang.org/x/crypto/ssh/terminal"
"gopkg.in/urfave/cli.v2"
"github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/logger"
"github.com/equinox-io/equinox"
"github.com/facebookgo/grace/gracenet"
"github.com/pkg/errors"
)
const (
@@ -30,7 +31,6 @@ dsCmJ/QZ6aw0w9qkkwEpne1Lmo6+0pGexZzFZOH6w5amShn+RXt7qkSid9iWlzGq
EKx0BZogHSor9Wy5VztdFaAaVbsJiCbO
-----END ECDSA PUBLIC KEY-----
`)
logger = log.CreateLogger()
)
// BinaryUpdated implements ExitCoder interface, the app will exit with status code 11
@@ -93,7 +93,12 @@ func checkForUpdateAndApply() UpdateOutcome {
}
func Update(_ *cli.Context) error {
updateOutcome := loggedUpdate()
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
updateOutcome := loggedUpdate(logger)
if updateOutcome.Error != nil {
return &statusErr{updateOutcome.Error}
}
@@ -107,13 +112,13 @@ func Update(_ *cli.Context) error {
}
// Checks for an update and applies it if one is available
func loggedUpdate() UpdateOutcome {
func loggedUpdate(logger logger.Service) UpdateOutcome {
updateOutcome := checkForUpdateAndApply()
if updateOutcome.Updated {
logger.Infof("cloudflared has been updated to version %s", updateOutcome.Version)
}
if updateOutcome.Error != nil {
logger.WithError(updateOutcome.Error).Error("update check failed")
logger.Errorf("update check failed: %s", updateOutcome.Error)
}
return updateOutcome
@@ -124,6 +129,7 @@ type AutoUpdater struct {
configurable *configurable
listeners *gracenet.Net
updateConfigChan chan *configurable
logger logger.Service
}
// AutoUpdaterConfigurable is the attributes of AutoUpdater that can be reconfigured during runtime
@@ -132,7 +138,7 @@ type configurable struct {
freq time.Duration
}
func NewAutoUpdater(freq time.Duration, listeners *gracenet.Net) *AutoUpdater {
func NewAutoUpdater(freq time.Duration, listeners *gracenet.Net, logger logger.Service) *AutoUpdater {
updaterConfigurable := &configurable{
enabled: true,
freq: freq,
@@ -145,6 +151,7 @@ func NewAutoUpdater(freq time.Duration, listeners *gracenet.Net) *AutoUpdater {
configurable: updaterConfigurable,
listeners: listeners,
updateConfigChan: make(chan *configurable),
logger: logger,
}
}
@@ -152,20 +159,20 @@ func (a *AutoUpdater) Run(ctx context.Context) error {
ticker := time.NewTicker(a.configurable.freq)
for {
if a.configurable.enabled {
updateOutcome := loggedUpdate()
updateOutcome := loggedUpdate(a.logger)
if updateOutcome.Updated {
os.Args = append(os.Args, "--is-autoupdated=true")
if IsSysV() {
// SysV doesn't have a mechanism to keep service alive, we have to restart the process
logger.Infof("Restarting service managed by SysV...")
a.logger.Info("Restarting service managed by SysV...")
pid, err := a.listeners.StartProcess()
if err != nil {
logger.WithError(err).Error("Unable to restart server automatically")
a.logger.Errorf("Unable to restart server automatically: %s", err)
return &statusErr{err: err}
}
// stop old process after autoupdate. Otherwise we create a new process
// after each update
logger.Infof("PID of the new process is %d", pid)
a.logger.Infof("PID of the new process is %d", pid)
}
return &statusSuccess{newVersion: updateOutcome.Version}
}
@@ -197,14 +204,14 @@ func (a *AutoUpdater) Update(newFreq time.Duration) {
a.updateConfigChan <- newConfigurable
}
func IsAutoupdateEnabled(c *cli.Context) bool {
if !SupportAutoUpdate() {
func IsAutoupdateEnabled(c *cli.Context, l logger.Service) bool {
if !SupportAutoUpdate(l) {
return false
}
return !c.Bool("no-autoupdate") && c.Duration("autoupdate-freq") != 0
}
func SupportAutoUpdate() bool {
func SupportAutoUpdate(logger logger.Service) bool {
if runtime.GOOS == "windows" {
logger.Info(noUpdateOnWindowsMessage)
return false

View File

@@ -4,13 +4,15 @@ import (
"context"
"testing"
"github.com/cloudflare/cloudflared/logger"
"github.com/facebookgo/grace/gracenet"
"github.com/stretchr/testify/assert"
)
func TestDisabledAutoUpdater(t *testing.T) {
listeners := &gracenet.Net{}
autoupdater := NewAutoUpdater(0, listeners)
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
autoupdater := NewAutoUpdater(0, listeners, logger)
ctx, cancel := context.WithCancel(context.Background())
errC := make(chan error)
go func() {

View File

@@ -12,8 +12,11 @@ import (
"time"
"unsafe"
"github.com/cloudflare/cloudflared/logger"
"github.com/pkg/errors"
cli "gopkg.in/urfave/cli.v2"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/eventlog"
@@ -65,6 +68,12 @@ func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
// 2. get ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
// This involves actually trying to start the service.
logger, err := logger.New()
if err != nil {
os.Exit(1)
return
}
isIntSess, err := svc.IsAnInteractiveSession()
if err != nil {
logger.Fatalf("failed to determine if we are running in an interactive session: %v", err)
@@ -97,9 +106,15 @@ type windowsService struct {
// called by the package code at the start of the service
func (s *windowsService) Execute(serviceArgs []string, r <-chan svc.ChangeRequest, statusChan chan<- svc.Status) (ssec bool, errno uint32) {
logger, err := logger.New()
if err != nil {
os.Exit(1)
return
}
elog, err := eventlog.Open(windowsServiceName)
if err != nil {
logger.WithError(err).Errorf("Cannot open event log for %s", windowsServiceName)
logger.Errorf("Cannot open event log for %s with error: %s", windowsServiceName, err)
return
}
defer elog.Close()
@@ -160,6 +175,11 @@ func (s *windowsService) Execute(serviceArgs []string, r <-chan svc.ChangeReques
}
func installWindowsService(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
logger.Infof("Installing Argo Tunnel Windows service")
exepath, err := os.Executable()
if err != nil {
@@ -168,7 +188,7 @@ func installWindowsService(c *cli.Context) error {
}
m, err := mgr.Connect()
if err != nil {
logger.WithError(err).Errorf("Cannot establish a connection to the service control manager")
logger.Errorf("Cannot establish a connection to the service control manager: %s", err)
return err
}
defer m.Disconnect()
@@ -189,18 +209,23 @@ func installWindowsService(c *cli.Context) error {
err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil {
s.Delete()
logger.WithError(err).Errorf("Cannot install event logger")
logger.Errorf("Cannot install event logger: %s", err)
return fmt.Errorf("SetupEventLogSource() failed: %s", err)
}
err = configRecoveryOption(s.Handle)
if err != nil {
logger.WithError(err).Errorf("Cannot set service recovery actions")
logger.Errorf("Cannot set service recovery actions: %s", err)
logger.Infof("See %s to manually configure service recovery actions", windowsServiceUrl)
}
return nil
}
func uninstallWindowsService(c *cli.Context) error {
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
logger.Infof("Uninstalling Argo Tunnel Windows Service")
m, err := mgr.Connect()
if err != nil {