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

@ -5,12 +5,12 @@ import (
"path/filepath"
"time"
"github.com/sirupsen/logrus"
"github.com/cloudflare/cloudflared/logger"
)
// DirectoryUploadManager is used to manage file uploads on an interval from a directory
type DirectoryUploadManager struct {
logger *logrus.Logger
logger logger.Service
uploader Uploader
rootDirectory string
sweepInterval time.Duration
@ -23,7 +23,7 @@ type DirectoryUploadManager struct {
// uploader is an Uploader to use as an actual uploading engine
// directory is the directory to sweep for files to upload
// sweepInterval is how often to iterate the directory and upload the files within
func NewDirectoryUploadManager(logger *logrus.Logger, uploader Uploader, directory string, sweepInterval time.Duration, shutdownC chan struct{}) *DirectoryUploadManager {
func NewDirectoryUploadManager(logger logger.Service, uploader Uploader, directory string, sweepInterval time.Duration, shutdownC chan struct{}) *DirectoryUploadManager {
workerCount := 10
manager := &DirectoryUploadManager{
logger: logger,
@ -97,7 +97,7 @@ func (m *DirectoryUploadManager) worker() {
return
case filepath := <-m.workQueue:
if err := m.Upload(filepath); err != nil {
m.logger.WithError(err).Error("Cannot upload file to s3 bucket")
m.logger.Errorf("Cannot upload file to s3 bucket: %s", err)
} else {
os.Remove(filepath)
}

View File

@ -9,7 +9,7 @@ import (
"testing"
"time"
"github.com/sirupsen/logrus"
"github.com/cloudflare/cloudflared/logger"
)
type MockUploader struct {
@ -49,7 +49,7 @@ func setupTestDirectory(t *testing.T) string {
func createUploadManager(t *testing.T, shouldFailUpload bool) *DirectoryUploadManager {
rootDirectory := setupTestDirectory(t)
uploader := NewMockUploader(shouldFailUpload)
logger := logrus.New()
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
shutdownC := make(chan struct{})
return NewDirectoryUploadManager(logger, uploader, rootDirectory, 1*time.Second, shutdownC)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/cloudflare/cloudflared/cmd/cloudflared/token"
"github.com/cloudflare/cloudflared/h2mux"
"github.com/cloudflare/cloudflared/logger"
"github.com/pkg/errors"
)
@ -129,13 +130,13 @@ func IsAccessResponse(resp *http.Response) bool {
}
// BuildAccessRequest builds an HTTP request with the Access token set
func BuildAccessRequest(options *StartOptions) (*http.Request, error) {
func BuildAccessRequest(options *StartOptions, logger logger.Service) (*http.Request, error) {
req, err := http.NewRequest(http.MethodGet, options.OriginURL, nil)
if err != nil {
return nil, err
}
token, err := token.FetchToken(req.URL)
token, err := token.FetchToken(req.URL, logger)
if err != nil {
return nil, err
}

View File

@ -9,8 +9,8 @@ import (
"sync"
"testing"
"github.com/cloudflare/cloudflared/logger"
ws "github.com/gorilla/websocket"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)
@ -43,7 +43,7 @@ func (s *testStreamer) Write(p []byte) (int, error) {
func TestStartClient(t *testing.T) {
message := "Good morning Austin! Time for another sunny day in the great state of Texas."
logger := logrus.New()
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
wsConn := NewWSConnection(logger, false)
ts := newTestWebSocketServer()
defer ts.Close()
@ -68,7 +68,7 @@ func TestStartServer(t *testing.T) {
t.Fatalf("Error starting listener: %v", err)
}
message := "Good morning Austin! Time for another sunny day in the great state of Texas."
logger := logrus.New()
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
shutdownC := make(chan struct{})
wsConn := NewWSConnection(logger, false)
ts := newTestWebSocketServer()

View File

@ -7,16 +7,16 @@ import (
"net/http"
"github.com/cloudflare/cloudflared/cmd/cloudflared/token"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/socks"
cfwebsocket "github.com/cloudflare/cloudflared/websocket"
"github.com/gorilla/websocket"
"github.com/sirupsen/logrus"
)
// Websocket is used to carry data via WS binary frames over the tunnel from client to the origin
// This implements the functions for glider proxy (sock5) and the carrier interface
type Websocket struct {
logger *logrus.Logger
logger logger.Service
isSocks bool
}
@ -35,7 +35,7 @@ func (d *wsdialer) Dial(address string) (io.ReadWriteCloser, *socks.AddrSpec, er
}
// NewWSConnection returns a new connection object
func NewWSConnection(logger *logrus.Logger, isSocks bool) Connection {
func NewWSConnection(logger logger.Service, isSocks bool) Connection {
return &Websocket{
logger: logger,
isSocks: isSocks,
@ -45,9 +45,9 @@ func NewWSConnection(logger *logrus.Logger, isSocks bool) Connection {
// ServeStream will create a Websocket client stream connection to the edge
// it blocks and writes the raw data from conn over the tunnel
func (ws *Websocket) ServeStream(options *StartOptions, conn io.ReadWriter) error {
wsConn, err := createWebsocketStream(options)
wsConn, err := createWebsocketStream(options, ws.logger)
if err != nil {
ws.logger.WithError(err).Errorf("failed to connect to %s", options.OriginURL)
ws.logger.Errorf("failed to connect to %s with error: %s", options.OriginURL, err)
return err
}
defer wsConn.Close()
@ -73,7 +73,7 @@ func (ws *Websocket) StartServer(listener net.Listener, remote string, shutdownC
// createWebsocketStream will create a WebSocket connection to stream data over
// It also handles redirects from Access and will present that flow if
// the token is not present on the request
func createWebsocketStream(options *StartOptions) (*cfwebsocket.Conn, error) {
func createWebsocketStream(options *StartOptions, logger logger.Service) (*cfwebsocket.Conn, error) {
req, err := http.NewRequest(http.MethodGet, options.OriginURL, nil)
if err != nil {
return nil, err
@ -83,7 +83,7 @@ func createWebsocketStream(options *StartOptions) (*cfwebsocket.Conn, error) {
wsConn, resp, err := cfwebsocket.ClientConnect(req, nil)
defer closeRespBody(resp)
if err != nil && IsAccessResponse(resp) {
wsConn, err = createAccessAuthenticatedStream(options)
wsConn, err = createAccessAuthenticatedStream(options, logger)
if err != nil {
return nil, err
}
@ -99,8 +99,8 @@ func createWebsocketStream(options *StartOptions) (*cfwebsocket.Conn, error) {
// this probably means the token in storage is invalid (expired/revoked). If that
// happens it deletes the token and runs the connection again, so the user can
// login again and generate a new one.
func createAccessAuthenticatedStream(options *StartOptions) (*websocket.Conn, error) {
wsConn, resp, err := createAccessWebSocketStream(options)
func createAccessAuthenticatedStream(options *StartOptions, logger logger.Service) (*websocket.Conn, error) {
wsConn, resp, err := createAccessWebSocketStream(options, logger)
defer closeRespBody(resp)
if err == nil {
return wsConn, nil
@ -118,7 +118,7 @@ func createAccessAuthenticatedStream(options *StartOptions) (*websocket.Conn, er
if err := token.RemoveTokenIfExists(originReq.URL); err != nil {
return nil, err
}
wsConn, resp, err = createAccessWebSocketStream(options)
wsConn, resp, err = createAccessWebSocketStream(options, logger)
defer closeRespBody(resp)
if err != nil {
return nil, err
@ -128,8 +128,8 @@ func createAccessAuthenticatedStream(options *StartOptions) (*websocket.Conn, er
}
// createAccessWebSocketStream builds an Access request and makes a connection
func createAccessWebSocketStream(options *StartOptions) (*websocket.Conn, *http.Response, error) {
req, err := BuildAccessRequest(options)
func createAccessWebSocketStream(options *StartOptions, logger logger.Service) (*websocket.Conn, *http.Response, error) {
req, err := BuildAccessRequest(options, logger)
if err != nil {
return nil, nil, err
}

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{}