AUTH-2596 added new logger package and replaced logrus
This commit is contained in:
parent
a908453aa4
commit
046be63253
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{}{}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"} {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
)
|
||||
|
||||
|
@ -43,8 +43,8 @@ func (c *Connection) Serve(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// Connect is used to establish connections with cloudflare's edge network
|
||||
func (c *Connection) Connect(ctx context.Context, parameters *tunnelpogs.ConnectParameters, logger *logrus.Entry) (tunnelpogs.ConnectResult, error) {
|
||||
tsClient, err := NewRPCClient(ctx, c.muxer, logger.WithField("rpc", "connect"), openStreamTimeout)
|
||||
func (c *Connection) Connect(ctx context.Context, parameters *tunnelpogs.ConnectParameters, logger logger.Service) (tunnelpogs.ConnectResult, error) {
|
||||
tsClient, err := NewRPCClient(ctx, c.muxer, logger, openStreamTimeout)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create new RPC connection")
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
|
||||
"github.com/cloudflare/cloudflared/edgediscovery"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/streamhandler"
|
||||
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
)
|
||||
|
@ -40,7 +40,7 @@ type EdgeManager struct {
|
|||
// state is attributes of ConnectionManager that can change during runtime.
|
||||
state *edgeManagerState
|
||||
|
||||
logger *logrus.Entry
|
||||
logger logger.Service
|
||||
|
||||
metrics *metrics
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func NewEdgeManager(
|
|||
tlsConfig *tls.Config,
|
||||
serviceDiscoverer *edgediscovery.Edge,
|
||||
cloudflaredConfig *CloudflaredConfig,
|
||||
logger *logrus.Logger,
|
||||
logger logger.Service,
|
||||
) *EdgeManager {
|
||||
return &EdgeManager{
|
||||
streamHandler: streamHandler,
|
||||
|
@ -84,7 +84,7 @@ func NewEdgeManager(
|
|||
cloudflaredConfig: cloudflaredConfig,
|
||||
serviceDiscoverer: serviceDiscoverer,
|
||||
state: newEdgeConnectionManagerState(edgeConnMgrConfigurable, userCredential),
|
||||
logger: logger.WithField("subsystem", "connectionManager"),
|
||||
logger: logger,
|
||||
metrics: newMetrics(packageNamespace, edgeManagerSubsystem),
|
||||
}
|
||||
}
|
||||
|
@ -109,16 +109,16 @@ func (em *EdgeManager) Run(ctx context.Context) error {
|
|||
if em.state.shouldCreateConnection(em.serviceDiscoverer.AvailableAddrs()) {
|
||||
if connErr := em.newConnection(ctx, connIndex); connErr != nil {
|
||||
if !connErr.ShouldRetry {
|
||||
em.logger.WithError(connErr).Error(em.noRetryMessage())
|
||||
em.logger.Errorf("connectionManager: %s with error: %s", em.noRetryMessage(), connErr)
|
||||
return connErr
|
||||
}
|
||||
em.logger.WithError(connErr).Error("cannot create new connection")
|
||||
em.logger.Errorf("connectionManager: cannot create new connection: %s", connErr)
|
||||
} else {
|
||||
connIndex++
|
||||
}
|
||||
} else if em.state.shouldReduceConnection() {
|
||||
if err := em.closeConnection(ctx); err != nil {
|
||||
em.logger.WithError(err).Error("cannot close connection")
|
||||
em.logger.Errorf("connectionManager: cannot close connection: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ func (em *EdgeManager) newConnection(ctx context.Context, index int) *tunnelpogs
|
|||
IsClient: true,
|
||||
HeartbeatInterval: configurable.HeartbeatInterval,
|
||||
MaxHeartbeats: configurable.MaxFailedHeartbeats,
|
||||
Logger: em.logger.WithField("subsystem", "muxer"),
|
||||
Logger: em.logger,
|
||||
}, em.metrics.activeStreams)
|
||||
if err != nil {
|
||||
retryConnection(fmt.Sprintf("couldn't perform handshake with edge: %v", err))
|
||||
|
@ -178,7 +178,7 @@ func (em *EdgeManager) newConnection(ctx context.Context, index int) *tunnelpogs
|
|||
}
|
||||
|
||||
em.state.newConnection(h2muxConn)
|
||||
em.logger.Infof("connected to %s", connResult.ConnectedTo())
|
||||
em.logger.Infof("connectionManager: connected to %s", connResult.ConnectedTo())
|
||||
|
||||
if connResult.ClientConfig() != nil {
|
||||
em.streamHandler.UseConfiguration(ctx, connResult.ClientConfig())
|
||||
|
@ -198,7 +198,7 @@ func (em *EdgeManager) closeConnection(ctx context.Context) error {
|
|||
|
||||
func (em *EdgeManager) serveConn(ctx context.Context, conn *Connection) {
|
||||
err := conn.Serve(ctx)
|
||||
em.logger.WithError(err).Warn("Connection closed")
|
||||
em.logger.Errorf("connectionManager: Connection closed: %s", err)
|
||||
em.state.closeConnection(conn)
|
||||
em.serviceDiscoverer.GiveBack(conn.addr)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
|
||||
"github.com/cloudflare/cloudflared/edgediscovery"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/streamhandler"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
)
|
||||
|
@ -48,7 +48,7 @@ var (
|
|||
func mockEdgeManager() *EdgeManager {
|
||||
newConfigChan := make(chan<- *pogs.ClientConfig)
|
||||
useConfigResultChan := make(<-chan *pogs.UseConfigurationResult)
|
||||
logger := logrus.New()
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
edge := edgediscovery.MockEdge(logger, []*net.TCPAddr{})
|
||||
return NewEdgeManager(
|
||||
streamhandler.NewStreamHandler(newConfigChan, useConfigResultChan, logger),
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
rpc "zombiezen.com/go/capnproto2/rpc"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
)
|
||||
|
@ -18,7 +18,7 @@ import (
|
|||
func NewRPCClient(
|
||||
ctx context.Context,
|
||||
muxer *h2mux.Muxer,
|
||||
logger *logrus.Entry,
|
||||
logger logger.Service,
|
||||
openStreamTimeout time.Duration,
|
||||
) (client tunnelpogs.TunnelServer_PogsClient, err error) {
|
||||
openStreamCtx, openStreamCancel := context.WithTimeout(ctx, openStreamTimeout)
|
||||
|
|
|
@ -11,17 +11,17 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/hello"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/validation"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Proxy is an HTTP server that proxies requests to a Client.
|
||||
type Proxy struct {
|
||||
client Client
|
||||
accessValidator *validation.Access
|
||||
logger *logrus.Logger
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
// NewInsecureProxy creates a Proxy that talks to a Client at an origin.
|
||||
|
@ -43,7 +43,12 @@ func NewInsecureProxy(ctx context.Context, origin string) (*Proxy, error) {
|
|||
return nil, errors.Wrap(err, "could not connect to the database")
|
||||
}
|
||||
|
||||
return &Proxy{client, nil, logrus.New()}, nil
|
||||
logger, err := logger.New()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
return &Proxy{client, nil, logger}, nil
|
||||
}
|
||||
|
||||
// NewSecureProxy creates a Proxy that talks to a Client at an origin.
|
||||
|
@ -90,7 +95,8 @@ func (proxy *Proxy) IsAllowed(r *http.Request, verbose ...bool) bool {
|
|||
// Warn administrators that invalid JWTs are being rejected. This is indicative
|
||||
// of either a misconfiguration of the CLI or a massive failure of upstream systems.
|
||||
if len(verbose) > 0 {
|
||||
proxy.httpLog(r, err).Error("Failed JWT authentication")
|
||||
cfRay := proxy.getRayHeader(r)
|
||||
proxy.logger.Infof("dbproxy: Failed JWT authentication: cf-ray: %s %s", cfRay, err)
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -234,13 +240,14 @@ func (proxy *Proxy) httpRespondErr(w http.ResponseWriter, r *http.Request, defau
|
|||
|
||||
proxy.httpRespond(w, r, status, err.Error())
|
||||
if len(err.Error()) > 0 {
|
||||
proxy.httpLog(r, err).Warn("Database proxy error")
|
||||
cfRay := proxy.getRayHeader(r)
|
||||
proxy.logger.Infof("dbproxy: Database proxy error: cf-ray: %s %s", cfRay, err)
|
||||
}
|
||||
}
|
||||
|
||||
// httpLog returns a logrus.Entry that is formatted to output a request Cf-ray.
|
||||
func (proxy *Proxy) httpLog(r *http.Request, err error) *logrus.Entry {
|
||||
return proxy.logger.WithContext(r.Context()).WithField("CF-RAY", r.Header.Get("Cf-ray")).WithError(err)
|
||||
// getRayHeader returns the request's Cf-ray header.
|
||||
func (proxy *Proxy) getRayHeader(r *http.Request) string {
|
||||
return r.Header.Get("Cf-ray")
|
||||
}
|
||||
|
||||
// httpError extracts common errors and returns an status code and friendly error.
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -58,15 +58,15 @@ var friendlyDNSErrorLines = []string{
|
|||
}
|
||||
|
||||
// EdgeDiscovery implements HA service discovery lookup.
|
||||
func edgeDiscovery(logger *logrus.Entry) ([][]*net.TCPAddr, error) {
|
||||
func edgeDiscovery(logger logger.Service) ([][]*net.TCPAddr, error) {
|
||||
_, addrs, err := netLookupSRV(srvService, srvProto, srvName)
|
||||
if err != nil {
|
||||
_, fallbackAddrs, fallbackErr := fallbackLookupSRV(srvService, srvProto, srvName)
|
||||
if fallbackErr != nil || len(fallbackAddrs) == 0 {
|
||||
// use the original DNS error `err` in messages, not `fallbackErr`
|
||||
logger.Errorln("Error looking up Cloudflare edge IPs: the DNS query failed:", err)
|
||||
logger.Errorf("Error looking up Cloudflare edge IPs: the DNS query failed: %s", err)
|
||||
for _, s := range friendlyDNSErrorLines {
|
||||
logger.Errorln(s)
|
||||
logger.Error(s)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "Could not lookup srv records on _%v._%v.%v", srvService, srvProto, srvName)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package allregions
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -19,7 +19,8 @@ func TestEdgeDiscovery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
addrLists, err := edgeDiscovery(logrus.New().WithFields(logrus.Fields{}))
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
addrLists, err := edgeDiscovery(l)
|
||||
assert.NoError(t, err)
|
||||
actualAddrSet := map[string]bool{}
|
||||
for _, addrs := range addrLists {
|
||||
|
|
|
@ -2,8 +2,6 @@ package allregions
|
|||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Region contains cloudflared edge addresses. The edge is partitioned into several regions for
|
||||
|
@ -59,7 +57,7 @@ func (r Region) GetUnusedIP(excluding *net.TCPAddr) *net.TCPAddr {
|
|||
// Use the address, assigning it to a proxy connection.
|
||||
func (r Region) Use(addr *net.TCPAddr, connID int) {
|
||||
if addr == nil {
|
||||
logrus.Errorf("Attempted to use nil address for connection %d", connID)
|
||||
//logrus.Errorf("Attempted to use nil address for connection %d", connID)
|
||||
return
|
||||
}
|
||||
r.connFor[addr] = InUse(connID)
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
)
|
||||
|
||||
// Regions stores Cloudflare edge network IPs, partitioned into two regions.
|
||||
|
@ -19,7 +19,7 @@ type Regions struct {
|
|||
// ------------------------------------
|
||||
|
||||
// ResolveEdge resolves the Cloudflare edge, returning all regions discovered.
|
||||
func ResolveEdge(logger *logrus.Entry) (*Regions, error) {
|
||||
func ResolveEdge(logger logger.Service) (*Regions, error) {
|
||||
addrLists, err := edgeDiscovery(logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -6,8 +6,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/cloudflare/cloudflared/edgediscovery/allregions"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -20,7 +19,7 @@ var errNoAddressesLeft = fmt.Errorf("There are no free edge addresses left")
|
|||
type Edge struct {
|
||||
regions *allregions.Regions
|
||||
sync.Mutex
|
||||
logger *logrus.Entry
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
|
@ -29,37 +28,34 @@ type Edge struct {
|
|||
|
||||
// ResolveEdge runs the initial discovery of the Cloudflare edge, finding Addrs that can be allocated
|
||||
// to connections.
|
||||
func ResolveEdge(l *logrus.Logger) (*Edge, error) {
|
||||
logger := l.WithField("subsystem", subsystem)
|
||||
regions, err := allregions.ResolveEdge(logger)
|
||||
func ResolveEdge(l logger.Service) (*Edge, error) {
|
||||
regions, err := allregions.ResolveEdge(l)
|
||||
if err != nil {
|
||||
return new(Edge), err
|
||||
}
|
||||
return &Edge{
|
||||
logger: logger,
|
||||
logger: l,
|
||||
regions: regions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StaticEdge creates a list of edge addresses from the list of hostnames. Mainly used for testing connectivity.
|
||||
func StaticEdge(l *logrus.Logger, hostnames []string) (*Edge, error) {
|
||||
logger := l.WithField("subsystem", subsystem)
|
||||
func StaticEdge(l logger.Service, hostnames []string) (*Edge, error) {
|
||||
regions, err := allregions.StaticEdge(hostnames)
|
||||
if err != nil {
|
||||
return new(Edge), err
|
||||
}
|
||||
return &Edge{
|
||||
logger: logger,
|
||||
logger: l,
|
||||
regions: regions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MockEdge creates a Cloudflare Edge from arbitrary TCP addresses. Used for testing.
|
||||
func MockEdge(l *logrus.Logger, addrs []*net.TCPAddr) *Edge {
|
||||
logger := l.WithField("subsystem", subsystem)
|
||||
func MockEdge(l logger.Service, addrs []*net.TCPAddr) *Edge {
|
||||
regions := allregions.NewNoResolve(addrs)
|
||||
return &Edge{
|
||||
logger: logger,
|
||||
logger: l,
|
||||
regions: regions,
|
||||
}
|
||||
}
|
||||
|
@ -83,24 +79,20 @@ func (ed *Edge) GetAddrForRPC() (*net.TCPAddr, error) {
|
|||
func (ed *Edge) GetAddr(connID int) (*net.TCPAddr, error) {
|
||||
ed.Lock()
|
||||
defer ed.Unlock()
|
||||
logger := ed.logger.WithFields(logrus.Fields{
|
||||
"connID": connID,
|
||||
"function": "GetAddr",
|
||||
})
|
||||
|
||||
// If this connection has already used an edge addr, return it.
|
||||
if addr := ed.regions.AddrUsedBy(connID); addr != nil {
|
||||
logger.Debug("Returning same address back to proxy connection")
|
||||
ed.logger.Debugf("edgediscovery - GetAddr: Returning same address back to proxy connection: connID: %d", connID)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// Otherwise, give it an unused one
|
||||
addr := ed.regions.GetUnusedAddr(nil, connID)
|
||||
if addr == nil {
|
||||
logger.Debug("No addresses left to give proxy connection")
|
||||
ed.logger.Debugf("edgediscovery - GetAddr: No addresses left to give proxy connection: connID: %d", connID)
|
||||
return nil, errNoAddressesLeft
|
||||
}
|
||||
logger.Debugf("Giving connection its new address %s", addr)
|
||||
ed.logger.Debugf("edgediscovery - GetAddr: Giving connection its new address %s: connID: %d", addr, connID)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
|
@ -108,10 +100,6 @@ func (ed *Edge) GetAddr(connID int) (*net.TCPAddr, error) {
|
|||
func (ed *Edge) GetDifferentAddr(connID int) (*net.TCPAddr, error) {
|
||||
ed.Lock()
|
||||
defer ed.Unlock()
|
||||
logger := ed.logger.WithFields(logrus.Fields{
|
||||
"connID": connID,
|
||||
"function": "GetDifferentAddr",
|
||||
})
|
||||
|
||||
oldAddr := ed.regions.AddrUsedBy(connID)
|
||||
if oldAddr != nil {
|
||||
|
@ -119,11 +107,11 @@ func (ed *Edge) GetDifferentAddr(connID int) (*net.TCPAddr, error) {
|
|||
}
|
||||
addr := ed.regions.GetUnusedAddr(oldAddr, connID)
|
||||
if addr == nil {
|
||||
logger.Debug("No addresses left to give proxy connection")
|
||||
ed.logger.Debugf("edgediscovery - GetDifferentAddr: No addresses left to give proxy connection: connID: %d", connID)
|
||||
// note: if oldAddr were not nil, it will become available on the next iteration
|
||||
return nil, errNoAddressesLeft
|
||||
}
|
||||
logger.Debugf("Giving connection its new address %s", addr)
|
||||
ed.logger.Debugf("edgediscovery - GetDifferentAddr: Giving connection its new address %s: connID: %d", addr, connID)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
|
@ -139,6 +127,6 @@ func (ed *Edge) AvailableAddrs() int {
|
|||
func (ed *Edge) GiveBack(addr *net.TCPAddr) bool {
|
||||
ed.Lock()
|
||||
defer ed.Unlock()
|
||||
ed.logger.WithField("function", "GiveBack").Debug("Address now unused")
|
||||
ed.logger.Debug("edgediscovery - GiveBack: Address now unused")
|
||||
return ed.regions.GiveBack(addr)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -32,7 +32,7 @@ var (
|
|||
)
|
||||
|
||||
func TestGiveBack(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0, &addr1, &addr2, &addr3})
|
||||
|
||||
// Give this connection an address
|
||||
|
@ -49,7 +49,7 @@ func TestGiveBack(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRPCAndProxyShareSingleEdgeIP(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
// Make an edge with a single IP
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0})
|
||||
|
@ -66,7 +66,7 @@ func TestRPCAndProxyShareSingleEdgeIP(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetAddrForRPC(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0, &addr1, &addr2, &addr3})
|
||||
|
||||
// Get a connection
|
||||
|
@ -84,7 +84,7 @@ func TestGetAddrForRPC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOnePerRegion(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
// Make an edge with only one address
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0, &addr1})
|
||||
|
@ -108,7 +108,7 @@ func TestOnePerRegion(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOnlyOneAddrLeft(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
// Make an edge with only one address
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0})
|
||||
|
@ -130,7 +130,7 @@ func TestOnlyOneAddrLeft(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNoAddrsLeft(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
// Make an edge with no addresses
|
||||
edge := MockEdge(l, []*net.TCPAddr{})
|
||||
|
@ -142,7 +142,7 @@ func TestNoAddrsLeft(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetAddr(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0, &addr1, &addr2, &addr3})
|
||||
|
||||
// Give this connection an address
|
||||
|
@ -158,7 +158,7 @@ func TestGetAddr(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGetDifferentAddr(t *testing.T) {
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
edge := MockEdge(l, []*net.TCPAddr{&addr0, &addr1, &addr2, &addr3})
|
||||
|
||||
// Give this connection an address
|
||||
|
|
10
go.mod
10
go.mod
|
@ -5,12 +5,14 @@ go 1.12
|
|||
require (
|
||||
github.com/BurntSushi/go-sumtype v0.0.0-20190304192233-fcb4a6205bdc // indirect
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3
|
||||
github.com/acmacalister/skittles v0.0.0-20160609003031-7423546701e1
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||
github.com/aws/aws-sdk-go v1.25.8
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
|
||||
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
|
||||
github.com/cloudflare/cfssl v0.0.0-20141119014638-2f7f44e802e2
|
||||
github.com/cloudflare/cfssl v0.0.0-20141119014638-2f7f44e802e2 // indirect
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
||||
github.com/coredns/coredns v1.2.0
|
||||
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73
|
||||
|
@ -37,7 +39,7 @@ require (
|
|||
github.com/kshvakov/clickhouse v1.3.11
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/lib/pq v1.2.0
|
||||
github.com/mattn/go-colorable v0.1.4
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.10 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.11.0
|
||||
github.com/mholt/caddy v0.0.0-20180807230124-d3b731e9255b // indirect
|
||||
|
@ -51,8 +53,8 @@ require (
|
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
|
||||
github.com/prometheus/common v0.7.0 // indirect
|
||||
github.com/prometheus/procfs v0.0.5 // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/tinylib/msgp v1.1.0 // indirect
|
||||
github.com/xo/dburl v0.0.0-20191005012637-293c3298d6c0
|
||||
|
|
3
go.sum
3
go.sum
|
@ -10,7 +10,10 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
|
|||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/acmacalister/skittles v0.0.0-20160609003031-7423546701e1 h1:RKnVV4C7qoN/sToLX2y1dqH7T6kKLMHcwRJlgwb9Ggk=
|
||||
github.com/acmacalister/skittles v0.0.0-20160609003031-7423546701e1/go.mod h1:gI5CyA/CEnS6eqNV22rqs4dG3aGfaSbXgPORIlwr2r0=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
@ -48,7 +48,7 @@ type MuxerConfig struct {
|
|||
// The minimum number of heartbeats to send before terminating the connection.
|
||||
MaxHeartbeats uint64
|
||||
// Logger to use
|
||||
Logger *log.Entry
|
||||
Logger logger.Service
|
||||
CompressionQuality CompressionSetting
|
||||
// Initial size for HTTP2 flow control windows
|
||||
DefaultWindowSize uint32
|
||||
|
@ -136,10 +136,10 @@ func Handshake(
|
|||
handshakeSetting := http2.Setting{ID: SettingMuxerMagic, Val: MuxerMagicEdge}
|
||||
compressionSetting := http2.Setting{ID: SettingCompression, Val: config.CompressionQuality.toH2Setting()}
|
||||
if CompressionIsSupported() {
|
||||
log.Debug("Compression is supported")
|
||||
config.Logger.Debug("muxer: Compression is supported")
|
||||
m.compressionQuality = config.CompressionQuality.getPreset()
|
||||
} else {
|
||||
log.Debug("Compression is not supported")
|
||||
config.Logger.Debug("muxer: Compression is not supported")
|
||||
compressionSetting = http2.Setting{ID: SettingCompression, Val: 0}
|
||||
}
|
||||
|
||||
|
@ -176,12 +176,12 @@ func Handshake(
|
|||
// Sanity check to enusre idelDuration is sane
|
||||
if idleDuration == 0 || idleDuration < defaultTimeout {
|
||||
idleDuration = defaultTimeout
|
||||
config.Logger.Warn("Minimum idle time has been adjusted to ", defaultTimeout)
|
||||
config.Logger.Infof("muxer: Minimum idle time has been adjusted to %d", defaultTimeout)
|
||||
}
|
||||
maxRetries := config.MaxHeartbeats
|
||||
if maxRetries == 0 {
|
||||
maxRetries = defaultRetries
|
||||
config.Logger.Warn("Minimum number of unacked heartbeats to send before closing the connection has been adjusted to ", maxRetries)
|
||||
config.Logger.Infof("muxer: Minimum number of unacked heartbeats to send before closing the connection has been adjusted to %d", maxRetries)
|
||||
}
|
||||
|
||||
compBytesBefore, compBytesAfter := NewAtomicCounter(0), NewAtomicCounter(0)
|
||||
|
|
|
@ -15,8 +15,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
@ -28,7 +28,7 @@ const (
|
|||
|
||||
func TestMain(m *testing.M) {
|
||||
if os.Getenv("VERBOSE") == "1" {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
//TODO: set log level
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func NewDefaultMuxerPair(t assert.TestingT, testName string, f MuxedStreamFunc)
|
|||
Handler: f,
|
||||
IsClient: true,
|
||||
Name: "origin",
|
||||
Logger: log.NewEntry(log.New()),
|
||||
Logger: logger.NewOutputWriter(logger.NewMockWriteManager()),
|
||||
DefaultWindowSize: (1 << 8) - 1,
|
||||
MaxWindowSize: (1 << 15) - 1,
|
||||
StreamWriteBufferMaxLen: 1024,
|
||||
|
@ -63,7 +63,7 @@ func NewDefaultMuxerPair(t assert.TestingT, testName string, f MuxedStreamFunc)
|
|||
Timeout: testHandshakeTimeout,
|
||||
IsClient: false,
|
||||
Name: "edge",
|
||||
Logger: log.NewEntry(log.New()),
|
||||
Logger: logger.NewOutputWriter(logger.NewMockWriteManager()),
|
||||
DefaultWindowSize: (1 << 8) - 1,
|
||||
MaxWindowSize: (1 << 15) - 1,
|
||||
StreamWriteBufferMaxLen: 1024,
|
||||
|
@ -86,7 +86,7 @@ func NewCompressedMuxerPair(t assert.TestingT, testName string, quality Compress
|
|||
IsClient: true,
|
||||
Name: "origin",
|
||||
CompressionQuality: quality,
|
||||
Logger: log.NewEntry(log.New()),
|
||||
Logger: logger.NewOutputWriter(logger.NewMockWriteManager()),
|
||||
HeartbeatInterval: defaultTimeout,
|
||||
MaxHeartbeats: defaultRetries,
|
||||
},
|
||||
|
@ -96,7 +96,7 @@ func NewCompressedMuxerPair(t assert.TestingT, testName string, quality Compress
|
|||
IsClient: false,
|
||||
Name: "edge",
|
||||
CompressionQuality: quality,
|
||||
Logger: log.NewEntry(log.New()),
|
||||
Logger: logger.NewOutputWriter(logger.NewMockWriteManager()),
|
||||
HeartbeatInterval: defaultTimeout,
|
||||
MaxHeartbeats: defaultRetries,
|
||||
},
|
||||
|
@ -301,6 +301,7 @@ func TestSingleStreamLargeResponseBody(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleStreams(t *testing.T) {
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
f := MuxedStreamFunc(func(stream *MuxedStream) error {
|
||||
if len(stream.Headers) != 1 {
|
||||
t.Fatalf("expected %d headers, got %d", 1, len(stream.Headers))
|
||||
|
@ -308,13 +309,13 @@ func TestMultipleStreams(t *testing.T) {
|
|||
if stream.Headers[0].Name != "client-token" {
|
||||
t.Fatalf("expected header name %s, got %s", "client-token", stream.Headers[0].Name)
|
||||
}
|
||||
log.Debugf("Got request for stream %s", stream.Headers[0].Value)
|
||||
l.Debugf("Got request for stream %s", stream.Headers[0].Value)
|
||||
stream.WriteHeaders([]Header{
|
||||
{Name: "response-token", Value: stream.Headers[0].Value},
|
||||
})
|
||||
log.Debugf("Wrote headers for stream %s", stream.Headers[0].Value)
|
||||
l.Debugf("Wrote headers for stream %s", stream.Headers[0].Value)
|
||||
stream.Write([]byte("OK"))
|
||||
log.Debugf("Wrote body for stream %s", stream.Headers[0].Value)
|
||||
l.Debugf("Wrote body for stream %s", stream.Headers[0].Value)
|
||||
return nil
|
||||
})
|
||||
muxPair := NewDefaultMuxerPair(t, t.Name(), f)
|
||||
|
@ -332,7 +333,7 @@ func TestMultipleStreams(t *testing.T) {
|
|||
[]Header{{Name: "client-token", Value: tokenString}},
|
||||
nil,
|
||||
)
|
||||
log.Debugf("Got headers for stream %d", tokenId)
|
||||
l.Debugf("Got headers for stream %d", tokenId)
|
||||
if err != nil {
|
||||
errorsC <- err
|
||||
return
|
||||
|
@ -370,7 +371,7 @@ func TestMultipleStreams(t *testing.T) {
|
|||
testFail := false
|
||||
for err := range errorsC {
|
||||
testFail = true
|
||||
log.Error(err)
|
||||
l.Errorf("%s", err)
|
||||
}
|
||||
if testFail {
|
||||
t.Fatalf("TestMultipleStreams failed")
|
||||
|
@ -448,6 +449,8 @@ func TestMultipleStreamsFlowControl(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGracefulShutdown(t *testing.T) {
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
sendC := make(chan struct{})
|
||||
responseBuf := bytes.Repeat([]byte("Hello world"), 65536)
|
||||
|
||||
|
@ -456,17 +459,17 @@ func TestGracefulShutdown(t *testing.T) {
|
|||
{Name: "response-header", Value: "responseValue"},
|
||||
})
|
||||
<-sendC
|
||||
log.Debugf("Writing %d bytes", len(responseBuf))
|
||||
l.Debugf("Writing %d bytes", len(responseBuf))
|
||||
stream.Write(responseBuf)
|
||||
stream.CloseWrite()
|
||||
log.Debugf("Wrote %d bytes", len(responseBuf))
|
||||
l.Debugf("Wrote %d bytes", len(responseBuf))
|
||||
// Reading from the stream will block until the edge closes its end of the stream.
|
||||
// Otherwise, we'll close the whole connection before receiving the 'stream closed'
|
||||
// message from the edge.
|
||||
// Graceful shutdown works if you omit this, it just gives spurious errors for now -
|
||||
// TODO ignore errors when writing 'stream closed' and we're shutting down.
|
||||
stream.Read([]byte{0})
|
||||
log.Debugf("Handler ends")
|
||||
l.Debugf("Handler ends")
|
||||
return nil
|
||||
})
|
||||
muxPair := NewDefaultMuxerPair(t, t.Name(), f)
|
||||
|
@ -483,7 +486,7 @@ func TestGracefulShutdown(t *testing.T) {
|
|||
muxPair.EdgeMux.Shutdown()
|
||||
close(sendC)
|
||||
responseBody := make([]byte, len(responseBuf))
|
||||
log.Debugf("Waiting for %d bytes", len(responseBuf))
|
||||
l.Debugf("Waiting for %d bytes", len(responseBuf))
|
||||
n, err := io.ReadFull(stream, responseBody)
|
||||
if err != nil {
|
||||
t.Fatalf("error from (*MuxedStream).Read with %d bytes read: %s", n, err)
|
||||
|
@ -676,6 +679,7 @@ func AssertIfPipeReadable(t *testing.T, pipe io.ReadCloser) {
|
|||
}
|
||||
|
||||
func TestMultipleStreamsWithDictionaries(t *testing.T) {
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
for q := CompressionNone; q <= CompressionMax; q++ {
|
||||
htmlBody := `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"` +
|
||||
|
@ -812,7 +816,7 @@ func TestMultipleStreamsWithDictionaries(t *testing.T) {
|
|||
testFail := false
|
||||
for err := range errorsC {
|
||||
testFail = true
|
||||
log.Error(err)
|
||||
l.Errorf("%s", err)
|
||||
}
|
||||
if testFail {
|
||||
t.Fatalf("TestMultipleStreams failed")
|
||||
|
@ -826,6 +830,8 @@ func TestMultipleStreamsWithDictionaries(t *testing.T) {
|
|||
}
|
||||
|
||||
func sampleSiteHandler(files map[string][]byte) MuxedStreamFunc {
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
return func(stream *MuxedStream) error {
|
||||
var contentType string
|
||||
var pathHeader Header
|
||||
|
@ -853,13 +859,13 @@ func sampleSiteHandler(files map[string][]byte) MuxedStreamFunc {
|
|||
stream.WriteHeaders([]Header{
|
||||
Header{Name: "content-type", Value: contentType},
|
||||
})
|
||||
log.Debugf("Wrote headers for stream %s", pathHeader.Value)
|
||||
l.Debugf("Wrote headers for stream %s", pathHeader.Value)
|
||||
file, ok := files[pathHeader.Value]
|
||||
if !ok {
|
||||
return fmt.Errorf("%s content is not preloaded", pathHeader.Value)
|
||||
}
|
||||
stream.Write(file)
|
||||
log.Debugf("Wrote body for stream %s", pathHeader.Value)
|
||||
l.Debugf("Wrote body for stream %s", pathHeader.Value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/golang-collections/collections/queue"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// data points used to compute average receive window and send window size
|
||||
|
@ -22,7 +21,7 @@ type muxMetricsUpdater interface {
|
|||
// metrics returns the latest metrics
|
||||
metrics() *MuxerMetrics
|
||||
// run is a blocking call to start the event loop
|
||||
run(logger *log.Entry) error
|
||||
run(logger logger.Service) error
|
||||
// updateRTTChan is called by muxReader to report new RTT measurements
|
||||
updateRTT(rtt *roundTripMeasurement)
|
||||
//updateReceiveWindowChan is called by muxReader and muxWriter when receiveWindow size is updated
|
||||
|
@ -139,34 +138,30 @@ func (updater *muxMetricsUpdaterImpl) metrics() *MuxerMetrics {
|
|||
return m
|
||||
}
|
||||
|
||||
func (updater *muxMetricsUpdaterImpl) run(parentLogger *log.Entry) error {
|
||||
logger := parentLogger.WithFields(log.Fields{
|
||||
"subsystem": "mux",
|
||||
"dir": "metrics",
|
||||
})
|
||||
defer logger.Debug("event loop finished")
|
||||
func (updater *muxMetricsUpdaterImpl) run(logger logger.Service) error {
|
||||
defer logger.Debug("mux - metrics: event loop finished")
|
||||
for {
|
||||
select {
|
||||
case <-updater.abortChan:
|
||||
logger.Infof("Stopping mux metrics updater")
|
||||
logger.Infof("mux - metrics: Stopping mux metrics updater")
|
||||
return nil
|
||||
case roundTripMeasurement := <-updater.updateRTTChan:
|
||||
go updater.rttData.update(roundTripMeasurement)
|
||||
logger.Debug("Update rtt")
|
||||
logger.Debug("mux - metrics: Update rtt")
|
||||
case receiveWindow := <-updater.updateReceiveWindowChan:
|
||||
go updater.receiveWindowData.update(receiveWindow)
|
||||
logger.Debug("Update receive window")
|
||||
logger.Debug("mux - metrics: Update receive window")
|
||||
case sendWindow := <-updater.updateSendWindowChan:
|
||||
go updater.sendWindowData.update(sendWindow)
|
||||
logger.Debug("Update send window")
|
||||
logger.Debug("mux - metrics: Update send window")
|
||||
case inBoundBytes := <-updater.updateInBoundBytesChan:
|
||||
// inBoundBytes is bytes/sec because the update interval is 1 sec
|
||||
go updater.inBoundRate.update(inBoundBytes)
|
||||
logger.Debugf("Inbound bytes %d", inBoundBytes)
|
||||
logger.Debugf("mux - metrics: Inbound bytes %d", inBoundBytes)
|
||||
case outBoundBytes := <-updater.updateOutBoundBytesChan:
|
||||
// outBoundBytes is bytes/sec because the update interval is 1 sec
|
||||
go updater.outBoundRate.update(outBoundBytes)
|
||||
logger.Debugf("Outbound bytes %d", outBoundBytes)
|
||||
logger.Debugf("mux - metrics: Outbound bytes %d", outBoundBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -91,7 +91,7 @@ func TestMuxMetricsUpdater(t *testing.T) {
|
|||
abortChan := make(chan struct{})
|
||||
compBefore, compAfter := NewAtomicCounter(0), NewAtomicCounter(0)
|
||||
m := newMuxMetricsUpdater(abortChan, compBefore, compAfter)
|
||||
logger := log.NewEntry(log.New())
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
go func() {
|
||||
errChan <- m.run(logger)
|
||||
|
|
|
@ -3,11 +3,12 @@ package h2mux
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
|
@ -67,12 +68,8 @@ func (r *MuxReader) Shutdown() <-chan struct{} {
|
|||
return done
|
||||
}
|
||||
|
||||
func (r *MuxReader) run(parentLogger *log.Entry) error {
|
||||
logger := parentLogger.WithFields(log.Fields{
|
||||
"subsystem": "mux",
|
||||
"dir": "read",
|
||||
})
|
||||
defer logger.Debug("event loop finished")
|
||||
func (r *MuxReader) run(logger logger.Service) error {
|
||||
defer logger.Debug("mux - read: event loop finished")
|
||||
|
||||
// routine to periodically update bytesRead
|
||||
go func() {
|
||||
|
@ -90,13 +87,13 @@ func (r *MuxReader) run(parentLogger *log.Entry) error {
|
|||
for {
|
||||
frame, err := r.f.ReadFrame()
|
||||
if err != nil {
|
||||
errLogger := logger.WithError(err)
|
||||
errorString := fmt.Sprintf("mux - read: %s", err)
|
||||
if errorDetail := r.f.ErrorDetail(); errorDetail != nil {
|
||||
errLogger = errLogger.WithField("errorDetail", errorDetail)
|
||||
errorString = fmt.Sprintf("%s: errorDetail: %s", errorString, errorDetail)
|
||||
}
|
||||
switch e := err.(type) {
|
||||
case http2.StreamError:
|
||||
errLogger.Warn("stream error")
|
||||
logger.Infof("%s: stream error", errorString)
|
||||
// Ideally we wouldn't return here, since that aborts the muxer.
|
||||
// We should communicate the error to the relevant MuxedStream
|
||||
// data structure, so that callers of MuxedStream.Read() and
|
||||
|
@ -104,25 +101,25 @@ func (r *MuxReader) run(parentLogger *log.Entry) error {
|
|||
// and keep the muxer going.
|
||||
return r.streamError(e.StreamID, e.Code)
|
||||
case http2.ConnectionError:
|
||||
errLogger.Warn("connection error")
|
||||
logger.Infof("%s: stream error", errorString)
|
||||
return r.connectionError(err)
|
||||
default:
|
||||
if isConnectionClosedError(err) {
|
||||
if r.streams.Len() == 0 {
|
||||
// don't log the error here -- that would just be extra noise
|
||||
logger.Debug("shutting down")
|
||||
logger.Debug("mux - read: shutting down")
|
||||
return nil
|
||||
}
|
||||
errLogger.Warn("connection closed unexpectedly")
|
||||
logger.Infof("%s: connection closed unexpectedly", errorString)
|
||||
return err
|
||||
} else {
|
||||
errLogger.Warn("frame read error")
|
||||
logger.Infof("%s: frame read error", errorString)
|
||||
return r.connectionError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
r.connActive.Signal()
|
||||
logger.WithField("data", frame).Debug("read frame")
|
||||
logger.Debugf("mux - read: read frame: data %v", frame)
|
||||
switch f := frame.(type) {
|
||||
case *http2.DataFrame:
|
||||
err = r.receiveFrameData(f, logger)
|
||||
|
@ -158,7 +155,7 @@ func (r *MuxReader) run(parentLogger *log.Entry) error {
|
|||
err = ErrUnexpectedFrameType
|
||||
}
|
||||
if err != nil {
|
||||
logger.WithField("data", frame).WithError(err).Debug("frame error")
|
||||
logger.Debugf("mux - read: read error: data %v", frame)
|
||||
return r.connectionError(err)
|
||||
}
|
||||
}
|
||||
|
@ -279,8 +276,7 @@ func (r *MuxReader) handleStream(stream *MuxedStream) {
|
|||
}
|
||||
|
||||
// Receives a data frame from a stream. A non-nil error is a connection error.
|
||||
func (r *MuxReader) receiveFrameData(frame *http2.DataFrame, parentLogger *log.Entry) error {
|
||||
logger := parentLogger.WithField("stream", frame.Header().StreamID)
|
||||
func (r *MuxReader) receiveFrameData(frame *http2.DataFrame, logger logger.Service) error {
|
||||
stream, err := r.getStreamForFrame(frame)
|
||||
if err != nil {
|
||||
return r.defaultStreamErrorHandler(err, frame.Header())
|
||||
|
@ -296,9 +292,9 @@ func (r *MuxReader) receiveFrameData(frame *http2.DataFrame, parentLogger *log.E
|
|||
if frame.Header().Flags.Has(http2.FlagDataEndStream) {
|
||||
if stream.receiveEOF() {
|
||||
r.streams.Delete(stream.streamID)
|
||||
logger.Debug("stream closed")
|
||||
logger.Debugf("mux - read: stream closed: streamID: %d", frame.Header().StreamID)
|
||||
} else {
|
||||
logger.Debug("shutdown receive side")
|
||||
logger.Debugf("mux - read: shutdown receive side: streamID: %d", frame.Header().StreamID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"io"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
)
|
||||
|
@ -72,12 +72,8 @@ func tsToPingData(ts int64) [8]byte {
|
|||
return pingData
|
||||
}
|
||||
|
||||
func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
||||
logger := parentLogger.WithFields(log.Fields{
|
||||
"subsystem": "mux",
|
||||
"dir": "write",
|
||||
})
|
||||
defer logger.Debug("event loop finished")
|
||||
func (w *MuxWriter) run(logger logger.Service) error {
|
||||
defer logger.Debug("mux - write: event loop finished")
|
||||
|
||||
// routine to periodically communicate bytesWrote
|
||||
go func() {
|
||||
|
@ -95,17 +91,17 @@ func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
|||
for {
|
||||
select {
|
||||
case <-w.abortChan:
|
||||
logger.Debug("aborting writer thread")
|
||||
logger.Debug("mux - write: aborting writer thread")
|
||||
return nil
|
||||
case errCode := <-w.goAwayChan:
|
||||
logger.Debug("sending GOAWAY code ", errCode)
|
||||
logger.Debugf("mux - write: sending GOAWAY code %v", errCode)
|
||||
err := w.f.WriteGoAway(w.streams.LastPeerStreamID(), errCode, []byte{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.idleTimer.MarkActive()
|
||||
case <-w.pingTimestamp.GetUpdateChan():
|
||||
logger.Debug("sending PING ACK")
|
||||
logger.Debug("mux - write: sending PING ACK")
|
||||
err := w.f.WritePing(true, tsToPingData(w.pingTimestamp.Get()))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -115,7 +111,7 @@ func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
|||
if !w.idleTimer.Retry() {
|
||||
return ErrConnectionDropped
|
||||
}
|
||||
logger.Debug("sending PING")
|
||||
logger.Debug("mux - write: sending PING")
|
||||
err := w.f.WritePing(false, tsToPingData(time.Now().UnixNano()))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -125,7 +121,7 @@ func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
|||
w.idleTimer.MarkActive()
|
||||
case <-w.streamErrors.GetSignalChan():
|
||||
for streamID, errCode := range w.streamErrors.GetErrors() {
|
||||
logger.WithField("stream", streamID).WithField("code", errCode).Debug("resetting stream")
|
||||
logger.Debugf("mux - write: resetting stream with code: %v streamID: %d", errCode, streamID)
|
||||
err := w.f.WriteRSTStream(streamID, errCode)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -145,19 +141,17 @@ func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
|||
if streamRequest.body != nil {
|
||||
go streamRequest.flushBody()
|
||||
}
|
||||
streamLogger := logger.WithField("stream", streamID)
|
||||
err := w.writeStreamData(streamRequest.stream, streamLogger)
|
||||
err := w.writeStreamData(streamRequest.stream, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.idleTimer.MarkActive()
|
||||
case streamID := <-w.readyStreamChan:
|
||||
streamLogger := logger.WithField("stream", streamID)
|
||||
stream, ok := w.streams.Get(streamID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
err := w.writeStreamData(stream, streamLogger)
|
||||
err := w.writeStreamData(stream, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -165,7 +159,7 @@ func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
|||
case useDict := <-w.useDictChan:
|
||||
err := w.writeUseDictionary(useDict)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("error writing use dictionary")
|
||||
logger.Errorf("mux - write: error writing use dictionary: %s", err)
|
||||
return err
|
||||
}
|
||||
w.idleTimer.MarkActive()
|
||||
|
@ -173,18 +167,18 @@ func (w *MuxWriter) run(parentLogger *log.Entry) error {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *MuxWriter) writeStreamData(stream *MuxedStream, logger *log.Entry) error {
|
||||
logger.Debug("writable")
|
||||
func (w *MuxWriter) writeStreamData(stream *MuxedStream, logger logger.Service) error {
|
||||
logger.Debugf("mux - write: writable: streamID: %d", stream.streamID)
|
||||
chunk := stream.getChunk()
|
||||
w.metricsUpdater.updateReceiveWindow(stream.getReceiveWindow())
|
||||
w.metricsUpdater.updateSendWindow(stream.getSendWindow())
|
||||
if chunk.sendHeadersFrame() {
|
||||
err := w.writeHeaders(chunk.streamID, chunk.headers)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("error writing headers")
|
||||
logger.Errorf("mux - write: error writing headers: %s: streamID: %d", err, stream.streamID)
|
||||
return err
|
||||
}
|
||||
logger.Debug("output headers")
|
||||
logger.Debugf("mux - write: output headers: streamID: %d", stream.streamID)
|
||||
}
|
||||
|
||||
if chunk.sendWindowUpdateFrame() {
|
||||
|
@ -195,22 +189,22 @@ func (w *MuxWriter) writeStreamData(stream *MuxedStream, logger *log.Entry) erro
|
|||
// window, unless the receiver treats this as a connection error"
|
||||
err := w.f.WriteWindowUpdate(chunk.streamID, chunk.windowUpdate)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("error writing window update")
|
||||
logger.Errorf("mux - write: error writing window update: %s: streamID: %d", err, stream.streamID)
|
||||
return err
|
||||
}
|
||||
logger.Debugf("increment receive window by %d", chunk.windowUpdate)
|
||||
logger.Debugf("mux - write: increment receive window by %d streamID: %d", chunk.windowUpdate, stream.streamID)
|
||||
}
|
||||
|
||||
for chunk.sendDataFrame() {
|
||||
payload, sentEOF := chunk.nextDataFrame(int(w.maxFrameSize))
|
||||
err := w.f.WriteData(chunk.streamID, sentEOF, payload)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("error writing data")
|
||||
logger.Errorf("mux - write: error writing data: %s: streamID: %d", err, stream.streamID)
|
||||
return err
|
||||
}
|
||||
// update the amount of data wrote
|
||||
w.bytesWrote.IncrementBy(uint64(len(payload)))
|
||||
logger.WithField("len", len(payload)).Debug("output data")
|
||||
logger.Errorf("mux - write: output data: %d: streamID: %d", len(payload), stream.streamID)
|
||||
|
||||
if sentEOF {
|
||||
if stream.readBuffer.Closed() {
|
||||
|
@ -218,15 +212,15 @@ func (w *MuxWriter) writeStreamData(stream *MuxedStream, logger *log.Entry) erro
|
|||
if !stream.gotReceiveEOF() {
|
||||
// the peer may send data that we no longer want to receive. Force them into the
|
||||
// closed state.
|
||||
logger.Debug("resetting stream")
|
||||
logger.Debugf("mux - write: resetting stream: streamID: %d", stream.streamID)
|
||||
w.f.WriteRSTStream(chunk.streamID, http2.ErrCodeNo)
|
||||
} else {
|
||||
// Half-open stream transitioned into closed
|
||||
logger.Debug("closing stream")
|
||||
logger.Debugf("mux - write: closing stream: streamID: %d", stream.streamID)
|
||||
}
|
||||
w.streams.Delete(chunk.streamID)
|
||||
} else {
|
||||
logger.Debug("closing stream write side")
|
||||
logger.Debugf("mux - write: closing stream write side: streamID: %d", stream.streamID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cloudflare/cloudflared/tlsconfig"
|
||||
)
|
||||
|
@ -91,7 +91,7 @@ const indexTemplate = `
|
|||
</html>
|
||||
`
|
||||
|
||||
func StartHelloWorldServer(logger *logrus.Logger, listener net.Listener, shutdownC <-chan struct{}) error {
|
||||
func StartHelloWorldServer(logger logger.Service, listener net.Listener, shutdownC <-chan struct{}) error {
|
||||
logger.Infof("Starting Hello World server at %s", listener.Addr())
|
||||
serverName := defaultServerName
|
||||
if hostname, err := os.Hostname(); err == nil {
|
||||
|
@ -148,7 +148,7 @@ func uptimeHandler(startTime time.Time) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// This handler will echo message
|
||||
func websocketHandler(logger *logrus.Logger, upgrader websocket.Upgrader) http.HandlerFunc {
|
||||
func websocketHandler(logger logger.Service, upgrader websocket.Upgrader) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
|
@ -158,12 +158,12 @@ func websocketHandler(logger *logrus.Logger, upgrader websocket.Upgrader) http.H
|
|||
for {
|
||||
mt, message, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("websocket read message error")
|
||||
logger.Errorf("websocket read message error: %s", err)
|
||||
break
|
||||
}
|
||||
|
||||
if err := conn.WriteMessage(mt, message); err != nil {
|
||||
logger.WithError(err).Error("websocket write message error")
|
||||
logger.Errorf("websocket write message error: %s", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
85
log/log.go
85
log/log.go
|
@ -1,85 +0,0 @@
|
|||
// this forks the logrus json formatter to rename msg -> message as that's the
|
||||
// expected field. Ideally the logger should make it easier for us.
|
||||
package log
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultTimestampFormat = time.RFC3339Nano
|
||||
)
|
||||
|
||||
type JSONFormatter struct {
|
||||
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
TimestampFormat string
|
||||
}
|
||||
|
||||
func CreateLogger() *logrus.Logger {
|
||||
logger := logrus.New()
|
||||
logger.Out = colorable.NewColorableStderr()
|
||||
logger.Formatter = &logrus.TextFormatter{ForceColors: runtime.GOOS == "windows"}
|
||||
return logger
|
||||
}
|
||||
|
||||
func (f *JSONFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
data := make(logrus.Fields, len(entry.Data)+3)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
// Otherwise errors are ignored by `encoding/json`
|
||||
// https://github.com/sirupsen/logrus/issues/137
|
||||
data[k] = v.Error()
|
||||
default:
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
prefixFieldClashes(data)
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
}
|
||||
|
||||
data["time"] = entry.Time.Format(timestampFormat)
|
||||
data["message"] = entry.Message
|
||||
data["level"] = entry.Level.String()
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
}
|
||||
|
||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
//
|
||||
// Would just silently drop the user provided level. Instead with this code
|
||||
// it'll logged as:
|
||||
//
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
func prefixFieldClashes(data logrus.Fields) {
|
||||
if t, ok := data["time"]; ok {
|
||||
data["fields.time"] = t
|
||||
}
|
||||
|
||||
if m, ok := data["msg"]; ok {
|
||||
data["fields.msg"] = m
|
||||
}
|
||||
|
||||
if l, ok := data["level"]; ok {
|
||||
data["fields.level"] = l
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alecthomas/units"
|
||||
)
|
||||
|
||||
// Option is to encaspulate actions that will be called by Parse and run later to build an Options struct
|
||||
type Option func(*Options) error
|
||||
|
||||
// Options is use to set logging configuration data
|
||||
type Options struct {
|
||||
logFileDirectory string
|
||||
maxFileSize units.Base2Bytes
|
||||
maxFileCount uint
|
||||
terminalOutputDisabled bool
|
||||
supportedFileLevels []Level
|
||||
supportedTerminalLevels []Level
|
||||
}
|
||||
|
||||
// DisableTerminal stops terminal output for the logger
|
||||
func DisableTerminal(disable bool) Option {
|
||||
return func(c *Options) error {
|
||||
c.terminalOutputDisabled = disable
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// File sets a custom file to log events
|
||||
func File(path string, size units.Base2Bytes, count uint) Option {
|
||||
return func(c *Options) error {
|
||||
c.logFileDirectory = path
|
||||
c.maxFileSize = size
|
||||
c.maxFileCount = count
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultFile configures the log options will the defaults
|
||||
func DefaultFile(directoryPath string) Option {
|
||||
return func(c *Options) error {
|
||||
size, err := units.ParseBase2Bytes("1MB")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.logFileDirectory = directoryPath
|
||||
c.maxFileSize = size
|
||||
c.maxFileCount = 5
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SupportedFileLevels sets the supported logging levels for the log file
|
||||
func SupportedFileLevels(supported []Level) Option {
|
||||
return func(c *Options) error {
|
||||
c.supportedFileLevels = supported
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SupportedTerminalevels sets the supported logging levels for the terminal output
|
||||
func SupportedTerminalevels(supported []Level) Option {
|
||||
return func(c *Options) error {
|
||||
c.supportedTerminalLevels = supported
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// LogLevelString sets the supported logging levels from a command line flag
|
||||
func LogLevelString(level string) Option {
|
||||
return func(c *Options) error {
|
||||
supported, err := ParseLevelString(level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.supportedFileLevels = supported
|
||||
c.supportedTerminalLevels = supported
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Parse builds the Options struct so the caller knows what actions should be run
|
||||
func Parse(opts ...Option) (*Options, error) {
|
||||
options := &Options{}
|
||||
for _, opt := range opts {
|
||||
if err := opt(options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return options, nil
|
||||
}
|
||||
|
||||
// New setups a new logger based on the options.
|
||||
// The default behavior is to write to standard out
|
||||
func New(opts ...Option) (Service, error) {
|
||||
config, err := Parse(opts...)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := NewOutputWriter(SharedWriteManager)
|
||||
if config.logFileDirectory != "" {
|
||||
l.Add(NewFileRollingWriter(config.logFileDirectory,
|
||||
"cloudflared",
|
||||
int64(config.maxFileSize),
|
||||
config.maxFileCount),
|
||||
NewDefaultFormatter(time.RFC3339Nano), config.supportedFileLevels...)
|
||||
}
|
||||
|
||||
if !config.terminalOutputDisabled {
|
||||
if len(config.supportedTerminalLevels) == 0 {
|
||||
l.Add(os.Stdout, NewTerminalFormatter(""), InfoLevel)
|
||||
l.Add(os.Stderr, NewTerminalFormatter(""), ErrorLevel, FatalLevel)
|
||||
} else {
|
||||
errLevels := []Level{}
|
||||
outLevels := []Level{}
|
||||
for _, level := range config.supportedTerminalLevels {
|
||||
if level == ErrorLevel || level == FatalLevel {
|
||||
errLevels = append(errLevels, level)
|
||||
} else {
|
||||
outLevels = append(outLevels, level)
|
||||
}
|
||||
}
|
||||
l.Add(os.Stdout, NewTerminalFormatter(""), outLevels...)
|
||||
l.Add(os.Stderr, NewTerminalFormatter(""), errLevels...)
|
||||
}
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// ParseLevelString returns the expected log levels based on the cmd flag
|
||||
func ParseLevelString(lvl string) ([]Level, error) {
|
||||
switch strings.ToLower(lvl) {
|
||||
case "fatal":
|
||||
return []Level{FatalLevel}, nil
|
||||
case "error":
|
||||
return []Level{FatalLevel, ErrorLevel}, nil
|
||||
case "info":
|
||||
return []Level{FatalLevel, ErrorLevel, InfoLevel}, nil
|
||||
case "debug":
|
||||
return []Level{FatalLevel, ErrorLevel, InfoLevel, DebugLevel}, nil
|
||||
}
|
||||
return []Level{}, fmt.Errorf("not a valid log level: %q", lvl)
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FileRollingWriter maintains a set of log files numbered in order
|
||||
// to keep a subset of log data to ensure it doesn't grow pass defined limits
|
||||
type FileRollingWriter struct {
|
||||
baseFileName string
|
||||
directory string
|
||||
maxFileSize int64
|
||||
maxFileCount uint
|
||||
fileHandle *os.File
|
||||
}
|
||||
|
||||
// NewFileRollingWriter creates a new rolling file writer.
|
||||
// directory is the working directory for the files
|
||||
// baseFileName is the log file name. This writer appends .log to the name for the file name
|
||||
// maxFileSize is the size in bytes of how large each file can be. Not a hard limit, general limit based after each write
|
||||
// maxFileCount is the number of rolled files to keep.
|
||||
func NewFileRollingWriter(directory, baseFileName string, maxFileSize int64, maxFileCount uint) *FileRollingWriter {
|
||||
return &FileRollingWriter{
|
||||
directory: directory,
|
||||
baseFileName: baseFileName,
|
||||
maxFileSize: maxFileSize,
|
||||
maxFileCount: maxFileCount,
|
||||
}
|
||||
}
|
||||
|
||||
// Write is an implementation of io.writer the rolls the file once it reaches its max size
|
||||
// It is expected the caller to Write is doing so in a thread safe manner (as WriteManager does).
|
||||
func (w *FileRollingWriter) Write(p []byte) (n int, err error) {
|
||||
logFile := buildPath(w.directory, w.baseFileName)
|
||||
if w.fileHandle == nil {
|
||||
h, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
w.fileHandle = h
|
||||
}
|
||||
|
||||
// get size for rolling check
|
||||
info, err := w.fileHandle.Stat()
|
||||
if err != nil {
|
||||
// failed to stat the file. Close the file handle and attempt to open a new handle on the next write
|
||||
w.Close()
|
||||
w.fileHandle = nil
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// write to the file
|
||||
written, err := w.fileHandle.Write(p)
|
||||
|
||||
// check if the file needs to be rolled
|
||||
if err == nil && info.Size()+int64(written) > w.maxFileSize {
|
||||
// close the file handle than do the renaming. A new one will be opened on the next write
|
||||
w.Close()
|
||||
w.rename(logFile, 1)
|
||||
}
|
||||
|
||||
return written, err
|
||||
}
|
||||
|
||||
// Close closes the file handle if it is open
|
||||
func (w *FileRollingWriter) Close() {
|
||||
if w.fileHandle != nil {
|
||||
w.fileHandle.Close()
|
||||
w.fileHandle = nil
|
||||
}
|
||||
}
|
||||
|
||||
// rename is how the files are rolled. It works recursively to move the base log file to the rolled ones
|
||||
// e.g. cloudflared.log -> cloudflared-1.log,
|
||||
// but if cloudflared-1.log already exists, it is renamed to cloudflared-2.log,
|
||||
// then the other files move in to their postion
|
||||
func (w *FileRollingWriter) rename(sourcePath string, index uint) {
|
||||
destinationPath := buildPath(w.directory, fmt.Sprintf("%s-%d", w.baseFileName, index))
|
||||
|
||||
// rolled to the max amount of files allowed on disk
|
||||
if index >= w.maxFileCount {
|
||||
os.Remove(destinationPath)
|
||||
}
|
||||
|
||||
// if the rolled path already exist, rename it to cloudflared-2.log, then do this one.
|
||||
// recursive call since the oldest one needs to be renamed, before the newer ones can be moved
|
||||
if exists(destinationPath) {
|
||||
w.rename(destinationPath, index+1)
|
||||
}
|
||||
|
||||
os.Rename(sourcePath, destinationPath)
|
||||
}
|
||||
|
||||
func buildPath(directory, fileName string) string {
|
||||
return filepath.Join(directory, fileName+".log")
|
||||
}
|
||||
|
||||
func exists(filePath string) bool {
|
||||
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFileWrite(t *testing.T) {
|
||||
fileName := "test_file"
|
||||
fileLog := fileName + ".log"
|
||||
testData := []byte(string("hello Dalton, how are you doing?"))
|
||||
defer func() {
|
||||
os.Remove(fileLog)
|
||||
}()
|
||||
|
||||
w := NewFileRollingWriter("", fileName, 1000, 2)
|
||||
defer w.Close()
|
||||
|
||||
l, err := w.Write(testData)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, l, len(testData), "expected write length and data length to match")
|
||||
|
||||
d, err := ioutil.ReadFile(fileLog)
|
||||
assert.FileExists(t, fileLog, "file doesn't exist at expected path")
|
||||
assert.Equal(t, d, testData, "expected data in file to match test data")
|
||||
}
|
||||
|
||||
func TestRolling(t *testing.T) {
|
||||
fileName := "test_file"
|
||||
firstFile := fileName + ".log"
|
||||
secondFile := fileName + "-1.log"
|
||||
thirdFile := fileName + "-2.log"
|
||||
|
||||
defer func() {
|
||||
os.Remove(firstFile)
|
||||
os.Remove(secondFile)
|
||||
os.Remove(thirdFile)
|
||||
}()
|
||||
|
||||
w := NewFileRollingWriter("", fileName, 1000, 2)
|
||||
defer w.Close()
|
||||
|
||||
for i := 99; i >= 1; i-- {
|
||||
testData := []byte(fmt.Sprintf("%d bottles of beer on the wall...", i))
|
||||
w.Write(testData)
|
||||
}
|
||||
assert.FileExists(t, firstFile, "first file doesn't exist as expected")
|
||||
assert.FileExists(t, secondFile, "second file doesn't exist as expected")
|
||||
assert.FileExists(t, thirdFile, "third file doesn't exist as expected")
|
||||
assert.False(t, exists(fileName+"-3.log"), "limited to two files and there is more")
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/acmacalister/skittles"
|
||||
)
|
||||
|
||||
// Level of logging
|
||||
type Level int
|
||||
|
||||
const (
|
||||
// InfoLevel is for standard log messages
|
||||
InfoLevel Level = iota
|
||||
|
||||
// DebugLevel is for messages that are intended for purposes debugging only
|
||||
DebugLevel
|
||||
|
||||
// ErrorLevel is for error message to indicte something has gone wrong
|
||||
ErrorLevel
|
||||
|
||||
// FatalLevel is for error message that log and kill the program with an os.exit(1)
|
||||
FatalLevel
|
||||
)
|
||||
|
||||
// Formatter is the base interface for formatting logging messages before writing them out
|
||||
type Formatter interface {
|
||||
Timestamp(Level, time.Time) string // format the timestamp string
|
||||
Content(Level, string) string // format content string (color for terminal, etc)
|
||||
}
|
||||
|
||||
// DefaultFormatter writes a simple structure timestamp and the message per log line
|
||||
type DefaultFormatter struct {
|
||||
format string
|
||||
}
|
||||
|
||||
// NewDefaultFormatter creates the standard log formatter
|
||||
// format is the time format to use for timestamp formatting
|
||||
func NewDefaultFormatter(format string) Formatter {
|
||||
return &DefaultFormatter{
|
||||
format: format,
|
||||
}
|
||||
}
|
||||
|
||||
// Timestamp formats a log line timestamp with a brackets around them
|
||||
func (f *DefaultFormatter) Timestamp(l Level, d time.Time) string {
|
||||
if f.format == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("[%s]: ", d.Format(f.format))
|
||||
}
|
||||
|
||||
// Content just writes the log line straight to the sources
|
||||
func (f *DefaultFormatter) Content(l Level, c string) string {
|
||||
return c
|
||||
}
|
||||
|
||||
// TerminalFormatter is setup for colored output
|
||||
type TerminalFormatter struct {
|
||||
format string
|
||||
}
|
||||
|
||||
// NewTerminalFormatter creates a Terminal formatter for colored output
|
||||
// format is the time format to use for timestamp formatting
|
||||
func NewTerminalFormatter(format string) Formatter {
|
||||
return &TerminalFormatter{
|
||||
format: format,
|
||||
}
|
||||
}
|
||||
|
||||
// Timestamp returns the log level with a matching color to the log type
|
||||
func (f *TerminalFormatter) Timestamp(l Level, d time.Time) string {
|
||||
t := ""
|
||||
switch l {
|
||||
case InfoLevel:
|
||||
t = skittles.Cyan("[INFO] ")
|
||||
case ErrorLevel:
|
||||
t = skittles.Red("[ERROR] ")
|
||||
case DebugLevel:
|
||||
t = skittles.Yellow("[DEBUG] ")
|
||||
case FatalLevel:
|
||||
t = skittles.Red("[FATAL] ")
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Content just writes the log line straight to the sources
|
||||
func (f *TerminalFormatter) Content(l Level, c string) string {
|
||||
return c
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package logger
|
||||
|
||||
import "sync"
|
||||
|
||||
// SharedWriteManager is a package level variable to allows multiple loggers to use the same write manager.
|
||||
// This is useful when multiple loggers will write to the same file to ensure they don't clobber each other.
|
||||
var SharedWriteManager = NewWriteManager()
|
||||
|
||||
type writeData struct {
|
||||
writeFunc func([]byte)
|
||||
data []byte
|
||||
}
|
||||
|
||||
// WriteManager is a logging service that handles managing multiple writing streams
|
||||
type WriteManager struct {
|
||||
shutdown chan struct{}
|
||||
writeChan chan writeData
|
||||
writers map[string]Service
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewWriteManager creates a write manager that implements OutputManager
|
||||
func NewWriteManager() OutputManager {
|
||||
m := &WriteManager{
|
||||
shutdown: make(chan struct{}),
|
||||
writeChan: make(chan writeData, 1000),
|
||||
}
|
||||
|
||||
go m.run()
|
||||
return m
|
||||
}
|
||||
|
||||
// Append adds a message to the writer runloop
|
||||
func (m *WriteManager) Append(data []byte, callback func([]byte)) {
|
||||
m.wg.Add(1)
|
||||
m.writeChan <- writeData{data: data, writeFunc: callback}
|
||||
}
|
||||
|
||||
// Shutdown stops the sync manager service
|
||||
func (m *WriteManager) Shutdown() {
|
||||
m.wg.Wait()
|
||||
close(m.shutdown)
|
||||
close(m.writeChan)
|
||||
}
|
||||
|
||||
// run is the main runloop that schedules log messages
|
||||
func (m *WriteManager) run() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-m.writeChan:
|
||||
if ok {
|
||||
event.writeFunc(event.data)
|
||||
m.wg.Done()
|
||||
}
|
||||
case <-m.shutdown:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriteManger(t *testing.T) {
|
||||
testData := []byte(string("hello Austin, how are you doing?"))
|
||||
waitChan := make(chan []byte)
|
||||
m := NewWriteManager()
|
||||
m.Append(testData, func(b []byte) {
|
||||
waitChan <- b
|
||||
})
|
||||
resp := <-waitChan
|
||||
assert.Equal(t, testData, resp)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package logger
|
||||
|
||||
// MockWriteManager does nothing and is provided for testing purposes
|
||||
type MockWriteManager struct {
|
||||
}
|
||||
|
||||
// NewMockWriteManager creates an OutputManager that does nothing for testing purposes
|
||||
func NewMockWriteManager() OutputManager {
|
||||
return &MockWriteManager{}
|
||||
}
|
||||
|
||||
// Append is a mock stub
|
||||
func (m *MockWriteManager) Append(data []byte, callback func([]byte)) {
|
||||
}
|
||||
|
||||
// Shutdown is a mock stub
|
||||
func (m *MockWriteManager) Shutdown() {
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// provided for testing
|
||||
var osExit = os.Exit
|
||||
|
||||
// OutputManager is used to sync data of Output
|
||||
type OutputManager interface {
|
||||
Append([]byte, func([]byte))
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
// Service is the logging service that is either a group or single log writer
|
||||
type Service interface {
|
||||
Error(message string)
|
||||
Info(message string)
|
||||
Debug(message string)
|
||||
Fatal(message string)
|
||||
|
||||
Errorf(format string, args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
type sourceGroup struct {
|
||||
writer io.Writer
|
||||
formatter Formatter
|
||||
levelsSupported []Level
|
||||
}
|
||||
|
||||
// OutputWriter is the standard logging implementation
|
||||
type OutputWriter struct {
|
||||
groups []sourceGroup
|
||||
syncWriter OutputManager
|
||||
}
|
||||
|
||||
// NewOutputWriter create a new logger
|
||||
func NewOutputWriter(syncWriter OutputManager) *OutputWriter {
|
||||
return &OutputWriter{
|
||||
syncWriter: syncWriter,
|
||||
groups: make([]sourceGroup, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// Add a writer and formatter to output to
|
||||
func (s *OutputWriter) Add(writer io.Writer, formatter Formatter, levels ...Level) {
|
||||
s.groups = append(s.groups, sourceGroup{writer: writer, formatter: formatter, levelsSupported: levels})
|
||||
}
|
||||
|
||||
// Error writes an error to the logging sources
|
||||
func (s *OutputWriter) Error(message string) {
|
||||
s.output(ErrorLevel, message)
|
||||
}
|
||||
|
||||
// Info writes an info string to the logging sources
|
||||
func (s *OutputWriter) Info(message string) {
|
||||
s.output(InfoLevel, message)
|
||||
}
|
||||
|
||||
// Debug writes a debug string to the logging sources
|
||||
func (s *OutputWriter) Debug(message string) {
|
||||
s.output(DebugLevel, message)
|
||||
}
|
||||
|
||||
// Fatal writes a error string to the logging sources and runs does an os.exit()
|
||||
func (s *OutputWriter) Fatal(message string) {
|
||||
s.output(FatalLevel, message)
|
||||
s.syncWriter.Shutdown() // waits for the pending logging to finish
|
||||
osExit(1)
|
||||
}
|
||||
|
||||
// Errorf writes a formatted error to the logging sources
|
||||
func (s *OutputWriter) Errorf(format string, args ...interface{}) {
|
||||
s.output(ErrorLevel, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Infof writes a formatted info statement to the logging sources
|
||||
func (s *OutputWriter) Infof(format string, args ...interface{}) {
|
||||
s.output(InfoLevel, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Debugf writes a formatted debug statement to the logging sources
|
||||
func (s *OutputWriter) Debugf(format string, args ...interface{}) {
|
||||
s.output(DebugLevel, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Fatalf writes a writes a formatted error statement and runs does an os.exit()
|
||||
func (s *OutputWriter) Fatalf(format string, args ...interface{}) {
|
||||
s.output(FatalLevel, fmt.Sprintf(format, args...))
|
||||
s.syncWriter.Shutdown() // waits for the pending logging to finish
|
||||
osExit(1)
|
||||
}
|
||||
|
||||
// output does the actual write to the sync manager
|
||||
func (s *OutputWriter) output(l Level, content string) {
|
||||
for _, group := range s.groups {
|
||||
if isSupported(group, l) {
|
||||
logLine := fmt.Sprintf("%s%s\n", group.formatter.Timestamp(l, time.Now()),
|
||||
group.formatter.Content(l, content))
|
||||
s.append(group, []byte(logLine))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *OutputWriter) append(group sourceGroup, logLine []byte) {
|
||||
s.syncWriter.Append(logLine, func(b []byte) {
|
||||
group.writer.Write(b)
|
||||
})
|
||||
}
|
||||
|
||||
// isSupported checks if the log level is supported
|
||||
func isSupported(group sourceGroup, l Level) bool {
|
||||
for _, level := range group.levelsSupported {
|
||||
if l == level {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Write implements io.Writer to support SetOutput of the log package
|
||||
func (s *OutputWriter) Write(p []byte) (n int, err error) {
|
||||
s.Info(string(p))
|
||||
return len(p), nil
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLogLevel(t *testing.T) {
|
||||
timeFormat := "2006-01-02"
|
||||
f := NewDefaultFormatter(timeFormat)
|
||||
m := NewWriteManager()
|
||||
|
||||
var testBuffer bytes.Buffer
|
||||
logger := NewOutputWriter(m)
|
||||
logger.Add(&testBuffer, f, InfoLevel, DebugLevel)
|
||||
|
||||
testTime := f.Timestamp(InfoLevel, time.Now())
|
||||
|
||||
testInfo := "hello Dalton, how are you doing?"
|
||||
logger.Info(testInfo)
|
||||
|
||||
tesErr := "hello Austin, how did it break today?"
|
||||
logger.Error(tesErr)
|
||||
|
||||
testDebug := "hello Bill, who are you?"
|
||||
logger.Debug(testDebug)
|
||||
|
||||
m.Shutdown()
|
||||
|
||||
lines := strings.Split(testBuffer.String(), "\n")
|
||||
assert.Len(t, lines, 3, "only expected two strings in the buffer")
|
||||
|
||||
infoLine := lines[0]
|
||||
debugLine := lines[1]
|
||||
|
||||
compareInfo := fmt.Sprintf("%s%s", testTime, testInfo)
|
||||
assert.Equal(t, compareInfo, infoLine, "expect the strings to match")
|
||||
|
||||
compareDebug := fmt.Sprintf("%s%s", testTime, testDebug)
|
||||
assert.Equal(t, compareDebug, debugLine, "expect the strings to match")
|
||||
}
|
||||
|
||||
func TestOutputWrite(t *testing.T) {
|
||||
timeFormat := "2006-01-02"
|
||||
f := NewDefaultFormatter(timeFormat)
|
||||
m := NewWriteManager()
|
||||
|
||||
var testBuffer bytes.Buffer
|
||||
logger := NewOutputWriter(m)
|
||||
logger.Add(&testBuffer, f, InfoLevel)
|
||||
|
||||
testData := "hello Bob Bork, how are you doing?"
|
||||
logger.Info(testData)
|
||||
testTime := f.Timestamp(InfoLevel, time.Now())
|
||||
|
||||
m.Shutdown()
|
||||
|
||||
scanner := bufio.NewScanner(&testBuffer)
|
||||
scanner.Scan()
|
||||
line := scanner.Text()
|
||||
assert.NoError(t, scanner.Err())
|
||||
|
||||
compareLine := fmt.Sprintf("%s%s", testTime, testData)
|
||||
assert.Equal(t, compareLine, line, "expect the strings to match")
|
||||
}
|
||||
|
||||
func TestFatalWrite(t *testing.T) {
|
||||
timeFormat := "2006-01-02"
|
||||
f := NewDefaultFormatter(timeFormat)
|
||||
m := NewWriteManager()
|
||||
|
||||
var testBuffer bytes.Buffer
|
||||
logger := NewOutputWriter(m)
|
||||
logger.Add(&testBuffer, f, FatalLevel)
|
||||
|
||||
oldOsExit := osExit
|
||||
defer func() { osExit = oldOsExit }()
|
||||
|
||||
var got int
|
||||
myExit := func(code int) {
|
||||
got = code
|
||||
}
|
||||
|
||||
osExit = myExit
|
||||
|
||||
testData := "so long y'all"
|
||||
logger.Fatal(testData)
|
||||
testTime := f.Timestamp(FatalLevel, time.Now())
|
||||
|
||||
scanner := bufio.NewScanner(&testBuffer)
|
||||
scanner.Scan()
|
||||
line := scanner.Text()
|
||||
assert.NoError(t, scanner.Err())
|
||||
|
||||
compareLine := fmt.Sprintf("%s%s", testTime, testData)
|
||||
assert.Equal(t, compareLine, line, "expect the strings to match")
|
||||
assert.Equal(t, got, 1, "exit code should be one for a fatal log")
|
||||
}
|
|
@ -12,9 +12,9 @@ import (
|
|||
|
||||
"golang.org/x/net/trace"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -22,7 +22,7 @@ const (
|
|||
startupTime = time.Millisecond * 500
|
||||
)
|
||||
|
||||
func ServeMetrics(l net.Listener, shutdownC <-chan struct{}, logger *logrus.Logger) (err error) {
|
||||
func ServeMetrics(l net.Listener, shutdownC <-chan struct{}, logger logger.Service) (err error) {
|
||||
var wg sync.WaitGroup
|
||||
// Metrics port is privileged, so no need for further access control
|
||||
trace.AuthRequest = func(*http.Request) (bool, bool) { return true, true }
|
||||
|
@ -43,7 +43,7 @@ func ServeMetrics(l net.Listener, shutdownC <-chan struct{}, logger *logrus.Logg
|
|||
defer wg.Done()
|
||||
err = server.Serve(l)
|
||||
}()
|
||||
logger.WithField("addr", fmt.Sprintf("%v/metrics", l.Addr())).Info("Starting metrics server")
|
||||
logger.Infof("Starting metrics server on %s", fmt.Sprintf("%v/metrics", l.Addr()))
|
||||
// server.Serve will hang if server.Shutdown is called before the server is
|
||||
// fully started up. So add artificial delay.
|
||||
time.Sleep(startupTime)
|
||||
|
@ -58,7 +58,7 @@ func ServeMetrics(l net.Listener, shutdownC <-chan struct{}, logger *logrus.Logg
|
|||
logger.Info("Metrics server stopped")
|
||||
return nil
|
||||
}
|
||||
logger.WithError(err).Error("Metrics server quit with error")
|
||||
logger.Errorf("Metrics server quit with error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cloudflare/cloudflared/buffer"
|
||||
"github.com/cloudflare/cloudflared/connection"
|
||||
"github.com/cloudflare/cloudflared/edgediscovery"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/signal"
|
||||
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
)
|
||||
|
@ -56,7 +56,7 @@ type Supervisor struct {
|
|||
nextConnectedIndex int
|
||||
nextConnectedSignal chan struct{}
|
||||
|
||||
logger *logrus.Entry
|
||||
logger logger.Service
|
||||
|
||||
jwtLock sync.RWMutex
|
||||
jwt []byte
|
||||
|
@ -99,7 +99,7 @@ func NewSupervisor(config *TunnelConfig, u uuid.UUID) (*Supervisor, error) {
|
|||
edgeIPs: edgeIPs,
|
||||
tunnelErrors: make(chan tunnelError),
|
||||
tunnelsConnecting: map[int]chan struct{}{},
|
||||
logger: config.Logger.WithField("subsystem", "supervisor"),
|
||||
logger: config.Logger,
|
||||
connDigest: make(map[uint8][]byte),
|
||||
bufferPool: buffer.NewPool(512 * 1024),
|
||||
}, nil
|
||||
|
@ -123,7 +123,7 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal *signal.Signal, re
|
|||
if timer, err := s.refreshAuth(ctx, refreshAuthBackoff, s.authenticate); err == nil {
|
||||
refreshAuthBackoffTimer = timer
|
||||
} else {
|
||||
logger.WithError(err).Errorf("initial refreshAuth failed, retrying in %v", refreshAuthRetryDuration)
|
||||
logger.Errorf("supervisor: initial refreshAuth failed, retrying in %v: %s", refreshAuthRetryDuration, err)
|
||||
refreshAuthBackoffTimer = time.After(refreshAuthRetryDuration)
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal *signal.Signal, re
|
|||
case tunnelError := <-s.tunnelErrors:
|
||||
tunnelsActive--
|
||||
if tunnelError.err != nil {
|
||||
logger.WithError(tunnelError.err).Warn("Tunnel disconnected due to error")
|
||||
logger.Infof("supervisor: Tunnel disconnected due to error: %s", tunnelError.err)
|
||||
tunnelsWaiting = append(tunnelsWaiting, tunnelError.index)
|
||||
s.waitForNextTunnel(tunnelError.index)
|
||||
|
||||
|
@ -165,7 +165,7 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal *signal.Signal, re
|
|||
case <-refreshAuthBackoffTimer:
|
||||
newTimer, err := s.refreshAuth(ctx, refreshAuthBackoff, s.authenticate)
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("Authentication failed")
|
||||
logger.Errorf("supervisor: Authentication failed: %s", err)
|
||||
// Permanent failure. Leave the `select` without setting the
|
||||
// channel to be non-null, so we'll never hit this case of the `select` again.
|
||||
continue
|
||||
|
@ -182,9 +182,9 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal *signal.Signal, re
|
|||
s.lastResolve = time.Now()
|
||||
s.resolverC = nil
|
||||
if result.err == nil {
|
||||
logger.Debug("Service discovery refresh complete")
|
||||
logger.Debug("supervisor: Service discovery refresh complete")
|
||||
} else {
|
||||
logger.WithError(result.err).Error("Service discovery error")
|
||||
logger.Errorf("supervisor: Service discovery error: %s", result.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ func (s *Supervisor) initialize(ctx context.Context, connectedSignal *signal.Sig
|
|||
s.lastResolve = time.Now()
|
||||
availableAddrs := int(s.edgeIPs.AvailableAddrs())
|
||||
if s.config.HAConnections > availableAddrs {
|
||||
logger.Warnf("You requested %d HA connections but I can give you at most %d.", s.config.HAConnections, availableAddrs)
|
||||
logger.Infof("You requested %d HA connections but I can give you at most %d.", s.config.HAConnections, availableAddrs)
|
||||
s.config.HAConnections = availableAddrs
|
||||
}
|
||||
|
||||
|
@ -355,12 +355,12 @@ func (s *Supervisor) refreshAuth(
|
|||
backoff *BackoffHandler,
|
||||
authenticate func(ctx context.Context, numPreviousAttempts int) (tunnelpogs.AuthOutcome, error),
|
||||
) (retryTimer <-chan time.Time, err error) {
|
||||
logger := s.config.Logger.WithField("subsystem", subsystemRefreshAuth)
|
||||
logger := s.config.Logger
|
||||
authOutcome, err := authenticate(ctx, backoff.Retries())
|
||||
if err != nil {
|
||||
s.config.Metrics.authFail.WithLabelValues(err.Error()).Inc()
|
||||
if duration, ok := backoff.GetBackoffDuration(ctx); ok {
|
||||
logger.WithError(err).Warnf("Retrying in %v", duration)
|
||||
logger.Debugf("refresh_auth: Retrying in %v: %s", duration, err)
|
||||
return backoff.BackoffTimer(), nil
|
||||
}
|
||||
return nil, err
|
||||
|
@ -376,13 +376,13 @@ func (s *Supervisor) refreshAuth(
|
|||
case tunnelpogs.AuthUnknown:
|
||||
duration := outcome.RefreshAfter()
|
||||
s.config.Metrics.authFail.WithLabelValues(outcome.Error()).Inc()
|
||||
logger.WithError(outcome).Warnf("Retrying in %v", duration)
|
||||
logger.Debugf("refresh_auth: Retrying in %v: %s", duration, outcome)
|
||||
return timeAfter(duration), nil
|
||||
case tunnelpogs.AuthFail:
|
||||
s.config.Metrics.authFail.WithLabelValues(outcome.Error()).Inc()
|
||||
return nil, outcome
|
||||
default:
|
||||
err := fmt.Errorf("Unexpected outcome type %T", authOutcome)
|
||||
err := fmt.Errorf("refresh_auth: Unexpected outcome type %T", authOutcome)
|
||||
s.config.Metrics.authFail.WithLabelValues(err.Error()).Inc()
|
||||
return nil, err
|
||||
}
|
||||
|
@ -405,7 +405,6 @@ func (s *Supervisor) authenticate(ctx context.Context, numPreviousAttempts int)
|
|||
return nil // noop
|
||||
})
|
||||
muxerConfig := s.config.muxerConfig(handler)
|
||||
muxerConfig.Logger = muxerConfig.Logger.WithField("subsystem", subsystemRefreshAuth)
|
||||
muxer, err := h2mux.Handshake(edgeConn, edgeConn, muxerConfig, s.config.Metrics.activeStreams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -417,7 +416,7 @@ func (s *Supervisor) authenticate(ctx context.Context, numPreviousAttempts int)
|
|||
<-muxer.Shutdown()
|
||||
}()
|
||||
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, s.logger.WithField("subsystem", subsystemRefreshAuth), openStreamTimeout)
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, s.logger, openStreamTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
)
|
||||
|
||||
func testConfig(logger *logrus.Logger) *TunnelConfig {
|
||||
func testConfig(logger logger.Service) *TunnelConfig {
|
||||
metrics := TunnelMetrics{}
|
||||
|
||||
metrics.authSuccess = prometheus.NewCounter(
|
||||
|
@ -40,8 +40,7 @@ func testConfig(logger *logrus.Logger) *TunnelConfig {
|
|||
}
|
||||
|
||||
func TestRefreshAuthBackoff(t *testing.T) {
|
||||
logger := logrus.New()
|
||||
logger.Level = logrus.ErrorLevel
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
var wait time.Duration
|
||||
timeAfter = func(d time.Duration) <-chan time.Time {
|
||||
|
@ -85,8 +84,7 @@ func TestRefreshAuthBackoff(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRefreshAuthSuccess(t *testing.T) {
|
||||
logger := logrus.New()
|
||||
logger.Level = logrus.ErrorLevel
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
var wait time.Duration
|
||||
timeAfter = func(d time.Duration) <-chan time.Time {
|
||||
|
@ -114,8 +112,7 @@ func TestRefreshAuthSuccess(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRefreshAuthUnknown(t *testing.T) {
|
||||
logger := logrus.New()
|
||||
logger.Level = logrus.ErrorLevel
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
var wait time.Duration
|
||||
timeAfter = func(d time.Duration) <-chan time.Time {
|
||||
|
@ -143,8 +140,7 @@ func TestRefreshAuthUnknown(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRefreshAuthFail(t *testing.T) {
|
||||
logger := logrus.New()
|
||||
logger.Level = logrus.ErrorLevel
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
s, err := NewSupervisor(testConfig(logger), uuid.New())
|
||||
if !assert.NoError(t, err) {
|
||||
|
|
|
@ -17,13 +17,13 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/cloudflare/cloudflared/buffer"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/buildinfo"
|
||||
"github.com/cloudflare/cloudflared/connection"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/signal"
|
||||
"github.com/cloudflare/cloudflared/streamhandler"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
|
@ -68,7 +68,8 @@ type TunnelConfig struct {
|
|||
IsAutoupdated bool
|
||||
IsFreeTunnel bool
|
||||
LBPool string
|
||||
Logger *log.Logger
|
||||
Logger logger.Service
|
||||
TransportLogger logger.Service
|
||||
MaxHeartbeats uint64
|
||||
Metrics *TunnelMetrics
|
||||
MetricsUpdateFreq time.Duration
|
||||
|
@ -79,7 +80,6 @@ type TunnelConfig struct {
|
|||
RunFromTerminal bool
|
||||
Tags []tunnelpogs.Tag
|
||||
TlsConfig *tls.Config
|
||||
TransportLogger *log.Logger
|
||||
UseDeclarativeTunnel bool
|
||||
WSGI bool
|
||||
// OriginUrl may not be used if a user specifies a unix socket.
|
||||
|
@ -144,7 +144,7 @@ func (c *TunnelConfig) muxerConfig(handler h2mux.MuxedStreamHandler) h2mux.Muxer
|
|||
IsClient: true,
|
||||
HeartbeatInterval: c.HeartbeatInterval,
|
||||
MaxHeartbeats: c.MaxHeartbeats,
|
||||
Logger: c.TransportLogger.WithFields(log.Fields{}),
|
||||
Logger: c.TransportLogger,
|
||||
CompressionQuality: h2mux.CompressionSetting(c.CompressionQuality),
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,6 @@ func ServeTunnelLoop(ctx context.Context,
|
|||
bufferPool *buffer.Pool,
|
||||
reconnectCh chan ReconnectSignal,
|
||||
) error {
|
||||
connectionLogger := config.Logger.WithField("connectionID", connectionID)
|
||||
config.Metrics.incrementHaConnections()
|
||||
defer config.Metrics.decrementHaConnections()
|
||||
backoff := BackoffHandler{MaxRetries: config.Retries}
|
||||
|
@ -214,7 +213,7 @@ func ServeTunnelLoop(ctx context.Context,
|
|||
ctx,
|
||||
credentialManager,
|
||||
config,
|
||||
connectionLogger,
|
||||
config.Logger,
|
||||
addr, connectionID,
|
||||
connectedFuse,
|
||||
&backoff,
|
||||
|
@ -224,7 +223,7 @@ func ServeTunnelLoop(ctx context.Context,
|
|||
)
|
||||
if recoverable {
|
||||
if duration, ok := backoff.GetBackoffDuration(ctx); ok {
|
||||
connectionLogger.Infof("Retrying in %s seconds", duration)
|
||||
config.Logger.Infof("Retrying in %s seconds: connectionID: %d", duration, connectionID)
|
||||
backoff.Backoff(ctx)
|
||||
continue
|
||||
}
|
||||
|
@ -237,7 +236,7 @@ func ServeTunnel(
|
|||
ctx context.Context,
|
||||
credentialManager ReconnectTunnelCredentialManager,
|
||||
config *TunnelConfig,
|
||||
logger *log.Entry,
|
||||
logger logger.Service,
|
||||
addr *net.TCPAddr,
|
||||
connectionID uint8,
|
||||
connectedFuse *h2mux.BooleanFuse,
|
||||
|
@ -267,14 +266,13 @@ func ServeTunnel(
|
|||
// Returns error from parsing the origin URL or handshake errors
|
||||
handler, originLocalIP, err := NewTunnelHandler(ctx, config, addr, connectionID, bufferPool)
|
||||
if err != nil {
|
||||
errLog := logger.WithError(err)
|
||||
switch err.(type) {
|
||||
case connection.DialError:
|
||||
errLog.Error("Unable to dial edge")
|
||||
logger.Errorf("Unable to dial edge: %s connectionID: %d", err, connectionID)
|
||||
case h2mux.MuxerHandshakeError:
|
||||
errLog.Error("Handshake failed with edge server")
|
||||
logger.Errorf("Handshake failed with edge server: %s connectionID: %d", err, connectionID)
|
||||
default:
|
||||
errLog.Error("Tunnel creation failure")
|
||||
logger.Errorf("Tunnel creation failure: %s connectionID: %d", err, connectionID)
|
||||
return err, false
|
||||
}
|
||||
return err, true
|
||||
|
@ -307,10 +305,10 @@ func ServeTunnel(
|
|||
}
|
||||
// log errors and proceed to RegisterTunnel
|
||||
if tokenErr != nil {
|
||||
logger.WithError(tokenErr).Error("Couldn't get reconnect token")
|
||||
logger.Errorf("Couldn't get reconnect token: %s", tokenErr)
|
||||
}
|
||||
if eventDigestErr != nil {
|
||||
logger.WithError(eventDigestErr).Error("Couldn't get event digest")
|
||||
logger.Errorf("Couldn't get event digest: %s", eventDigestErr)
|
||||
}
|
||||
}
|
||||
return RegisterTunnel(serveCtx, credentialManager, handler.muxer, config, logger, connectionID, originLocalIP, u)
|
||||
|
@ -365,7 +363,7 @@ func ServeTunnel(
|
|||
logger.Info("Already connected to this server, selecting a different one")
|
||||
return err, true
|
||||
case serverRegisterTunnelError:
|
||||
logger.WithError(castedErr.cause).Error("Register tunnel error from server side")
|
||||
logger.Errorf("Register tunnel error from server side: %s", castedErr.cause)
|
||||
// Don't send registration error return from server to Sentry. They are
|
||||
// logged on server side
|
||||
if incidents := config.IncidentLookup.ActiveIncidents(); len(incidents) > 0 {
|
||||
|
@ -373,17 +371,17 @@ func ServeTunnel(
|
|||
}
|
||||
return castedErr.cause, !castedErr.permanent
|
||||
case clientRegisterTunnelError:
|
||||
logger.WithError(castedErr.cause).Error("Register tunnel error on client side")
|
||||
logger.Errorf("Register tunnel error on client side: %s", castedErr.cause)
|
||||
return err, true
|
||||
case muxerShutdownError:
|
||||
logger.Info("Muxer shutdown")
|
||||
return err, true
|
||||
case *ReconnectSignal:
|
||||
logger.Warnf("Restarting due to reconnect signal in %d seconds", castedErr.Delay)
|
||||
logger.Infof("Restarting due to reconnect signal in %d seconds", castedErr.Delay)
|
||||
castedErr.DelayBeforeReconnect()
|
||||
return err, true
|
||||
default:
|
||||
logger.WithError(err).Error("Serve tunnel error")
|
||||
logger.Errorf("Serve tunnel error: %s", err)
|
||||
return err, true
|
||||
}
|
||||
}
|
||||
|
@ -395,13 +393,13 @@ func RegisterTunnel(
|
|||
credentialManager ReconnectTunnelCredentialManager,
|
||||
muxer *h2mux.Muxer,
|
||||
config *TunnelConfig,
|
||||
logger *log.Entry,
|
||||
logger logger.Service,
|
||||
connectionID uint8,
|
||||
originLocalIP string,
|
||||
uuid uuid.UUID,
|
||||
) error {
|
||||
config.TransportLogger.Debug("initiating RPC stream to register")
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger.WithField("subsystem", "rpc-register"), openStreamTimeout)
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger, openStreamTimeout)
|
||||
if err != nil {
|
||||
// RPC stream open error
|
||||
return newClientRegisterTunnelError(err, config.Metrics.rpcFail, register)
|
||||
|
@ -432,14 +430,14 @@ func ReconnectTunnel(
|
|||
eventDigest, connDigest []byte,
|
||||
muxer *h2mux.Muxer,
|
||||
config *TunnelConfig,
|
||||
logger *log.Entry,
|
||||
logger logger.Service,
|
||||
connectionID uint8,
|
||||
originLocalIP string,
|
||||
uuid uuid.UUID,
|
||||
credentialManager ReconnectTunnelCredentialManager,
|
||||
) error {
|
||||
config.TransportLogger.Debug("initiating RPC stream to reconnect")
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger.WithField("subsystem", "rpc-reconnect"), openStreamTimeout)
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger, openStreamTimeout)
|
||||
if err != nil {
|
||||
// RPC stream open error
|
||||
return newClientRegisterTunnelError(err, config.Metrics.rpcFail, reconnect)
|
||||
|
@ -467,7 +465,7 @@ func ReconnectTunnel(
|
|||
|
||||
func processRegistrationSuccess(
|
||||
config *TunnelConfig,
|
||||
logger *log.Entry,
|
||||
logger logger.Service,
|
||||
connectionID uint8,
|
||||
registration *tunnelpogs.TunnelRegistration,
|
||||
name registerRPCName,
|
||||
|
@ -486,10 +484,10 @@ func processRegistrationSuccess(
|
|||
if isTrialTunnel := config.Hostname == ""; isTrialTunnel {
|
||||
if url, err := url.Parse(registration.Url); err == nil {
|
||||
for _, line := range asciiBox(trialZoneMsg(url.String()), 2) {
|
||||
logger.Infoln(line)
|
||||
logger.Info(line)
|
||||
}
|
||||
} else {
|
||||
logger.Errorln("Failed to connect tunnel, please try again.")
|
||||
logger.Error("Failed to connect tunnel, please try again.")
|
||||
return fmt.Errorf("empty URL in response from Cloudflare edge")
|
||||
}
|
||||
}
|
||||
|
@ -514,10 +512,10 @@ func processRegisterTunnelError(err tunnelpogs.TunnelRegistrationError, metrics
|
|||
}
|
||||
}
|
||||
|
||||
func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration, logger *log.Logger) error {
|
||||
func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration, logger logger.Service) error {
|
||||
logger.Debug("initiating RPC stream to unregister")
|
||||
ctx := context.Background()
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, logger.WithField("subsystem", "rpc-unregister"), openStreamTimeout)
|
||||
tunnelServer, err := connection.NewRPCClient(ctx, muxer, logger, openStreamTimeout)
|
||||
if err != nil {
|
||||
// RPC stream open error
|
||||
return err
|
||||
|
@ -532,16 +530,16 @@ func LogServerInfo(
|
|||
promise tunnelrpc.ServerInfo_Promise,
|
||||
connectionID uint8,
|
||||
metrics *TunnelMetrics,
|
||||
logger *log.Entry,
|
||||
logger logger.Service,
|
||||
) {
|
||||
serverInfoMessage, err := promise.Struct()
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("Failed to retrieve server information")
|
||||
logger.Errorf("Failed to retrieve server information: %s", err)
|
||||
return
|
||||
}
|
||||
serverInfo, err := tunnelpogs.UnmarshalServerInfo(serverInfoMessage)
|
||||
if err != nil {
|
||||
logger.WithError(err).Warn("Failed to retrieve server information")
|
||||
logger.Errorf("Failed to retrieve server information: %s", err)
|
||||
return
|
||||
}
|
||||
logger.Infof("Connected to %s", serverInfo.LocationName)
|
||||
|
@ -558,7 +556,7 @@ type TunnelHandler struct {
|
|||
metrics *TunnelMetrics
|
||||
// connectionID is only used by metrics, and prometheus requires labels to be string
|
||||
connectionID string
|
||||
logger *log.Logger
|
||||
logger logger.Service
|
||||
noChunkedEncoding bool
|
||||
|
||||
bufferPool *buffer.Pool
|
||||
|
@ -736,7 +734,7 @@ func (h *TunnelHandler) isEventStream(response *http.Response) bool {
|
|||
}
|
||||
|
||||
func (h *TunnelHandler) writeErrorResponse(stream *h2mux.MuxedStream, err error) {
|
||||
h.logger.WithError(err).Error("HTTP request error")
|
||||
h.logger.Errorf("HTTP request error: %s", err)
|
||||
stream.WriteHeaders([]h2mux.Header{
|
||||
{Name: ":status", Value: "502"},
|
||||
h2mux.CreateResponseMetaHeader(h2mux.ResponseMetaHeaderField, h2mux.ResponseSourceCloudflared),
|
||||
|
@ -746,41 +744,39 @@ func (h *TunnelHandler) writeErrorResponse(stream *h2mux.MuxedStream, err error)
|
|||
}
|
||||
|
||||
func (h *TunnelHandler) logRequest(req *http.Request, cfRay string, lbProbe bool) {
|
||||
logger := log.NewEntry(h.logger)
|
||||
logger := h.logger
|
||||
if cfRay != "" {
|
||||
logger = logger.WithField("CF-RAY", cfRay)
|
||||
logger.Debugf("%s %s %s", req.Method, req.URL, req.Proto)
|
||||
logger.Debugf("CF-RAY: %s %s %s %s", cfRay, req.Method, req.URL, req.Proto)
|
||||
} else if lbProbe {
|
||||
logger.Debugf("Load Balancer health check %s %s %s", req.Method, req.URL, req.Proto)
|
||||
logger.Debugf("CF-RAY: %s Load Balancer health check %s %s %s", cfRay, req.Method, req.URL, req.Proto)
|
||||
} else {
|
||||
logger.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto)
|
||||
logger.Infof("CF-RAY: %s All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", cfRay, req.Method, req.URL, req.Proto)
|
||||
}
|
||||
logger.Debugf("Request Headers %+v", req.Header)
|
||||
logger.Debugf("CF-RAY: %s Request Headers %+v", cfRay, req.Header)
|
||||
|
||||
if contentLen := req.ContentLength; contentLen == -1 {
|
||||
logger.Debugf("Request Content length unknown")
|
||||
logger.Debugf("CF-RAY: %s Request Content length unknown", cfRay)
|
||||
} else {
|
||||
logger.Debugf("Request content length %d", contentLen)
|
||||
logger.Debugf("CF-RAY: %s Request content length %d", cfRay, contentLen)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TunnelHandler) logResponseOk(r *http.Response, cfRay string, lbProbe bool) {
|
||||
h.metrics.incrementResponses(h.connectionID, "200")
|
||||
logger := log.NewEntry(h.logger)
|
||||
logger := h.logger
|
||||
if cfRay != "" {
|
||||
logger = logger.WithField("CF-RAY", cfRay)
|
||||
logger.Debugf("%s", r.Status)
|
||||
logger.Debugf("CF-RAY: %s %s", cfRay, r.Status)
|
||||
} else if lbProbe {
|
||||
logger.Debugf("Response to Load Balancer health check %s", r.Status)
|
||||
} else {
|
||||
logger.Infof("%s", r.Status)
|
||||
}
|
||||
logger.Debugf("Response Headers %+v", r.Header)
|
||||
logger.Debugf("CF-RAY: %s Response Headers %+v", cfRay, r.Header)
|
||||
|
||||
if contentLen := r.ContentLength; contentLen == -1 {
|
||||
logger.Debugf("Response content length unknown")
|
||||
logger.Debugf("CF-RAY: %s Response content length unknown", cfRay)
|
||||
} else {
|
||||
logger.Debugf("Response content length %d", contentLen)
|
||||
logger.Debugf("CF-RAY: %s Response content length %d", cfRay, contentLen)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/cloudflare/cloudflared/buffer"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/hello"
|
||||
"github.com/cloudflare/cloudflared/log"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/websocket"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -101,14 +101,14 @@ type WebsocketService struct {
|
|||
shutdownC chan struct{}
|
||||
}
|
||||
|
||||
func NewWebSocketService(tlsConfig *tls.Config, url *url.URL) (OriginService, error) {
|
||||
func NewWebSocketService(tlsConfig *tls.Config, url *url.URL, logger logger.Service) (OriginService, error) {
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot start Websocket Proxy Server")
|
||||
}
|
||||
shutdownC := make(chan struct{})
|
||||
go func() {
|
||||
websocket.StartProxyServer(log.CreateLogger(), listener, url.String(), shutdownC, websocket.DefaultStreamHandler)
|
||||
websocket.StartProxyServer(logger, listener, url.String(), shutdownC, websocket.DefaultStreamHandler)
|
||||
}()
|
||||
return &WebsocketService{
|
||||
tlsConfig: tlsConfig,
|
||||
|
@ -157,14 +157,14 @@ type HelloWorldService struct {
|
|||
bufferPool *buffer.Pool
|
||||
}
|
||||
|
||||
func NewHelloWorldService(transport http.RoundTripper) (OriginService, error) {
|
||||
func NewHelloWorldService(transport http.RoundTripper, logger logger.Service) (OriginService, error) {
|
||||
listener, err := hello.CreateTLSListener("127.0.0.1:")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot start Hello World Server")
|
||||
}
|
||||
shutdownC := make(chan struct{})
|
||||
go func() {
|
||||
hello.StartHelloWorldServer(log.CreateLogger(), listener, shutdownC)
|
||||
hello.StartHelloWorldServer(logger, listener, shutdownC)
|
||||
}()
|
||||
return &HelloWorldService{
|
||||
client: transport,
|
||||
|
|
|
@ -3,7 +3,7 @@ package sshlog
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
)
|
||||
|
||||
//empty manager implements the Manager but does nothing (for testing and to disable logging unless the logs are set)
|
||||
|
@ -18,11 +18,11 @@ func NewEmptyManager() Manager {
|
|||
return &emptyManager{}
|
||||
}
|
||||
|
||||
func (m *emptyManager) NewLogger(name string, logger *logrus.Logger) (io.WriteCloser, error) {
|
||||
func (m *emptyManager) NewLogger(name string, logger logger.Service) (io.WriteCloser, error) {
|
||||
return &emptyWriteCloser{}, nil
|
||||
}
|
||||
|
||||
func (m *emptyManager) NewSessionLogger(name string, logger *logrus.Logger) (io.WriteCloser, error) {
|
||||
func (m *emptyManager) NewSessionLogger(name string, logger logger.Service) (io.WriteCloser, error) {
|
||||
return &emptyWriteCloser{}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -24,7 +24,7 @@ type Logger struct {
|
|||
filename string
|
||||
file *os.File
|
||||
writeBuffer *bufio.Writer
|
||||
logger *logrus.Logger
|
||||
logger logger.Service
|
||||
flushInterval time.Duration
|
||||
maxFileSize int64
|
||||
done chan struct{}
|
||||
|
@ -35,10 +35,10 @@ type Logger struct {
|
|||
// drained and closed when the caller is finished, so instances should call
|
||||
// Close when finished with this Logger instance. Writes will be flushed to disk
|
||||
// every second (fsync). filename is the name of the logfile to be created. The
|
||||
// logger variable is a logrus that will log all i/o, filesystem error etc, that
|
||||
// logger variable is a logger service that will log all i/o, filesystem error etc, that
|
||||
// that shouldn't end execution of the logger, but are useful to report to the
|
||||
// caller.
|
||||
func NewLogger(filename string, logger *logrus.Logger, flushInterval time.Duration, maxFileSize int64) (*Logger, error) {
|
||||
func NewLogger(filename string, logger logger.Service, flushInterval time.Duration, maxFileSize int64) (*Logger, error) {
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger can't be nil")
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ func (l *Logger) writer() {
|
|||
select {
|
||||
case <-ticker.C:
|
||||
if err := l.write(); err != nil {
|
||||
l.logger.Errorln(err)
|
||||
l.logger.Errorf("%s", err)
|
||||
}
|
||||
case <-l.done:
|
||||
return
|
||||
|
|
|
@ -8,20 +8,21 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
)
|
||||
|
||||
const logFileName = "test-logger.log"
|
||||
|
||||
func createLogger(t *testing.T) *Logger {
|
||||
os.Remove(logFileName)
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
logger, err := NewLogger(logFileName, l, time.Millisecond, 1024)
|
||||
if err != nil {
|
||||
t.Fatal("couldn't create the logger!", err)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// AUTH-2115 TODO: fix this test
|
||||
//func TestWrite(t *testing.T) {
|
||||
// testStr := "hi"
|
||||
|
|
|
@ -5,13 +5,13 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
)
|
||||
|
||||
// Manager be managing logs bruh
|
||||
type Manager interface {
|
||||
NewLogger(string, *logrus.Logger) (io.WriteCloser, error)
|
||||
NewSessionLogger(string, *logrus.Logger) (io.WriteCloser, error)
|
||||
NewLogger(string, logger.Service) (io.WriteCloser, error)
|
||||
NewSessionLogger(string, logger.Service) (io.WriteCloser, error)
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
|
@ -25,10 +25,10 @@ func New(baseDirectory string) Manager {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *manager) NewLogger(name string, logger *logrus.Logger) (io.WriteCloser, error) {
|
||||
func (m *manager) NewLogger(name string, logger logger.Service) (io.WriteCloser, error) {
|
||||
return NewLogger(filepath.Join(m.baseDirectory, name), logger, time.Second, defaultFileSizeLimit)
|
||||
}
|
||||
|
||||
func (m *manager) NewSessionLogger(name string, logger *logrus.Logger) (io.WriteCloser, error) {
|
||||
func (m *manager) NewSessionLogger(name string, logger logger.Service) (io.WriteCloser, error) {
|
||||
return NewSessionLogger(filepath.Join(m.baseDirectory, name), logger, time.Second, defaultFileSizeLimit)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package sshlog
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
capnp "zombiezen.com/go/capnproto2"
|
||||
"zombiezen.com/go/capnproto2/pogs"
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ type sessionLogData struct {
|
|||
}
|
||||
|
||||
// NewSessionLogger creates a new session logger by encapsulating a Logger object and writing capnp encoded messages to it
|
||||
func NewSessionLogger(filename string, logger *logrus.Logger, flushInterval time.Duration, maxFileSize int64) (*SessionLogger, error) {
|
||||
func NewSessionLogger(filename string, logger logger.Service, flushInterval time.Duration, maxFileSize int64) (*SessionLogger, error) {
|
||||
l, err := NewLogger(filename, logger, flushInterval, maxFileSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
capnp "zombiezen.com/go/capnproto2"
|
||||
)
|
||||
|
||||
|
@ -13,7 +13,7 @@ const sessionLogFileName = "test-session-logger.log"
|
|||
|
||||
func createSessionLogger(t *testing.T) *SessionLogger {
|
||||
os.Remove(sessionLogFileName)
|
||||
l := logrus.New()
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
logger, err := NewSessionLogger(sessionLogFileName, l, time.Millisecond, 1024)
|
||||
if err != nil {
|
||||
t.Fatal("couldn't create the logger!", err)
|
||||
|
|
|
@ -19,8 +19,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
rsaFilename = "ssh_host_rsa_key"
|
||||
ecdsaFilename = "ssh_host_ecdsa_key"
|
||||
rsaFilename = "ssh_host_rsa_key"
|
||||
ecdsaFilename = "ssh_host_ecdsa_key"
|
||||
)
|
||||
|
||||
var defaultHostKeyDir = filepath.Join(".cloudflared", "host_keys")
|
||||
|
@ -68,7 +68,7 @@ func (s *SSHProxy) configureRSAKey(basePath string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
s.logger.Debug("Created new RSA SSH host key: ", keyPath)
|
||||
s.logger.Debugf("Created new RSA SSH host key: %s", keyPath)
|
||||
}
|
||||
if err := s.SetOption(ssh.HostKeyFile(keyPath)); err != nil {
|
||||
return errors.Wrap(err, "Could not set SSH RSA host key")
|
||||
|
@ -98,7 +98,7 @@ func (s *SSHProxy) configureECDSAKey(basePath string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
s.logger.Debug("Created new ECDSA SSH host key: ", keyPath)
|
||||
s.logger.Debugf("Created new ECDSA SSH host key: %s", keyPath)
|
||||
}
|
||||
if err := s.SetOption(ssh.HostKeyFile(keyPath)); err != nil {
|
||||
return errors.Wrap(err, "Could not set SSH ECDSA host key")
|
||||
|
|
|
@ -15,12 +15,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/sshgen"
|
||||
"github.com/cloudflare/cloudflared/sshlog"
|
||||
"github.com/gliderlabs/ssh"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
|
@ -66,7 +66,7 @@ func (c sshConn) Close() error {
|
|||
type SSHProxy struct {
|
||||
ssh.Server
|
||||
hostname string
|
||||
logger *logrus.Logger
|
||||
logger logger.Service
|
||||
shutdownC chan struct{}
|
||||
caCert ssh.PublicKey
|
||||
logManager sshlog.Manager
|
||||
|
@ -78,7 +78,7 @@ type SSHPreamble struct {
|
|||
}
|
||||
|
||||
// New creates a new SSHProxy and configures its host keys and authentication by the data provided
|
||||
func New(logManager sshlog.Manager, logger *logrus.Logger, version, localAddress, hostname, hostKeyDir string, shutdownC chan struct{}, idleTimeout, maxTimeout time.Duration) (*SSHProxy, error) {
|
||||
func New(logManager sshlog.Manager, logger logger.Service, version, localAddress, hostname, hostKeyDir string, shutdownC chan struct{}, idleTimeout, maxTimeout time.Duration) (*SSHProxy, error) {
|
||||
sshProxy := SSHProxy{
|
||||
hostname: hostname,
|
||||
logger: logger,
|
||||
|
@ -112,7 +112,7 @@ func (s *SSHProxy) Start() error {
|
|||
go func() {
|
||||
<-s.shutdownC
|
||||
if err := s.Close(); err != nil {
|
||||
s.logger.WithError(err).Error("Cannot close SSH server")
|
||||
s.logger.Errorf("Cannot close SSH server: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -141,9 +141,9 @@ func (s *SSHProxy) connCallback(ctx ssh.Context, conn net.Conn) net.Conn {
|
|||
preamble, err := s.readPreamble(conn)
|
||||
if err != nil {
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||
s.logger.Warn("Could not establish session. Client likely does not have --destination set and is using old-style ssh config")
|
||||
s.logger.Info("Could not establish session. Client likely does not have --destination set and is using old-style ssh config")
|
||||
} else if err != io.EOF {
|
||||
s.logger.WithError(err).Error("failed to read SSH preamble")
|
||||
s.logger.Errorf("failed to read SSH preamble: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ func (s *SSHProxy) connCallback(ctx ssh.Context, conn net.Conn) net.Conn {
|
|||
|
||||
logger, sessionID, err := s.auditLogger()
|
||||
if err != nil {
|
||||
s.logger.WithError(err).Error("failed to configure logger")
|
||||
s.logger.Errorf("failed to configure logger: %s", err)
|
||||
return nil
|
||||
}
|
||||
ctx.SetValue(sshContextEventLogger, logger)
|
||||
|
@ -175,14 +175,14 @@ func (s *SSHProxy) channelHandler(srv *ssh.Server, conn *gossh.ServerConn, newCh
|
|||
msg := fmt.Sprintf("channel type %s is not supported", newChan.ChannelType())
|
||||
s.logger.Info(msg)
|
||||
if err := newChan.Reject(gossh.UnknownChannelType, msg); err != nil {
|
||||
s.logger.WithError(err).Error("Error rejecting SSH channel")
|
||||
s.logger.Errorf("Error rejecting SSH channel: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
localChan, localChanReqs, err := newChan.Accept()
|
||||
if err != nil {
|
||||
s.logger.WithError(err).Error("Failed to accept session channel")
|
||||
s.logger.Errorf("Failed to accept session channel: %s", err)
|
||||
return
|
||||
}
|
||||
defer localChan.Close()
|
||||
|
@ -196,7 +196,7 @@ func (s *SSHProxy) channelHandler(srv *ssh.Server, conn *gossh.ServerConn, newCh
|
|||
|
||||
remoteChan, remoteChanReqs, err := client.OpenChannel(newChan.ChannelType(), newChan.ExtraData())
|
||||
if err != nil {
|
||||
s.logger.WithError(err).Error("Failed to open remote channel")
|
||||
s.logger.Errorf("Failed to open remote channel: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -211,13 +211,13 @@ func (s *SSHProxy) proxyChannel(localChan, remoteChan gossh.Channel, localChanRe
|
|||
done := make(chan struct{}, 2)
|
||||
go func() {
|
||||
if _, err := io.Copy(localChan, remoteChan); err != nil {
|
||||
s.logger.WithError(err).Error("remote to local copy error")
|
||||
s.logger.Errorf("remote to local copy error: %s", err)
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
go func() {
|
||||
if _, err := io.Copy(remoteChan, localChan); err != nil {
|
||||
s.logger.WithError(err).Error("local to remote copy error")
|
||||
s.logger.Errorf("local to remote copy error: %s", err)
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
@ -227,12 +227,12 @@ func (s *SSHProxy) proxyChannel(localChan, remoteChan gossh.Channel, localChanRe
|
|||
localStderr := localChan.Stderr()
|
||||
go func() {
|
||||
if _, err := io.Copy(remoteStderr, localStderr); err != nil {
|
||||
s.logger.WithError(err).Error("stderr local to remote copy error")
|
||||
s.logger.Errorf("stderr local to remote copy error: %s", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
if _, err := io.Copy(localStderr, remoteStderr); err != nil {
|
||||
s.logger.WithError(err).Error("stderr remote to local copy error")
|
||||
s.logger.Errorf("stderr remote to local copy error: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -247,7 +247,7 @@ func (s *SSHProxy) proxyChannel(localChan, remoteChan gossh.Channel, localChanRe
|
|||
return
|
||||
}
|
||||
if err := s.forwardChannelRequest(remoteChan, req); err != nil {
|
||||
s.logger.WithError(err).Error("Failed to forward request")
|
||||
s.logger.Errorf("Failed to forward request: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ func (s *SSHProxy) proxyChannel(localChan, remoteChan gossh.Channel, localChanRe
|
|||
return
|
||||
}
|
||||
if err := s.forwardChannelRequest(localChan, req); err != nil {
|
||||
s.logger.WithError(err).Error("Failed to forward request")
|
||||
s.logger.Errorf("Failed to forward request: %s", err)
|
||||
return
|
||||
}
|
||||
case <-done:
|
||||
|
@ -278,7 +278,7 @@ func (s *SSHProxy) readPreamble(conn net.Conn) (*SSHPreamble, error) {
|
|||
}
|
||||
defer func() {
|
||||
if err := conn.SetReadDeadline(time.Time{}); err != nil {
|
||||
s.logger.WithError(err).Error("Failed to unset conn read deadline")
|
||||
s.logger.Errorf("Failed to unset conn read deadline: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -341,7 +341,7 @@ func (s *SSHProxy) dialDestination(ctx ssh.Context) (*gossh.Client, error) {
|
|||
|
||||
signer, err := s.genSSHSigner(preamble.JWT)
|
||||
if err != nil {
|
||||
s.logger.WithError(err).Error("Failed to generate signed short lived cert")
|
||||
s.logger.Errorf("Failed to generate signed short lived cert: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
s.logger.Debugf("Short lived certificate for %s connecting to %s:\n\n%s", ctx.User(), preamble.Destination, gossh.MarshalAuthorizedKey(signer.PublicKey()))
|
||||
|
@ -356,7 +356,7 @@ func (s *SSHProxy) dialDestination(ctx ssh.Context) (*gossh.Client, error) {
|
|||
|
||||
client, err := gossh.Dial("tcp", preamble.Destination, clientConfig)
|
||||
if err != nil {
|
||||
s.logger.WithError(err).Info("Failed to connect to destination SSH server")
|
||||
s.logger.Errorf("Failed to connect to destination SSH server: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
|
@ -421,7 +421,7 @@ func (s *SSHProxy) logChannelRequest(req *gossh.Request, conn *gossh.ServerConn,
|
|||
case "exec":
|
||||
var payload struct{ Value string }
|
||||
if err := gossh.Unmarshal(req.Payload, &payload); err != nil {
|
||||
s.logger.WithError(err).Errorf("Failed to unmarshal channel request payload: %s:%s", req.Type, req.Payload)
|
||||
s.logger.Errorf("Failed to unmarshal channel request payload: %s:%s with error: %s", req.Type, req.Payload, err)
|
||||
}
|
||||
event = payload.Value
|
||||
|
||||
|
@ -481,11 +481,11 @@ func (s *SSHProxy) logAuditEvent(conn *gossh.ServerConn, event, eventType string
|
|||
}
|
||||
data, err := json.Marshal(&ae)
|
||||
if err != nil {
|
||||
s.logger.WithError(err).Error("Failed to marshal audit event. malformed audit object")
|
||||
s.logger.Errorf("Failed to marshal audit event. malformed audit object: %s", err)
|
||||
return
|
||||
}
|
||||
line := string(data) + "\n"
|
||||
if _, err := writer.Write([]byte(line)); err != nil {
|
||||
s.logger.WithError(err).Error("Failed to write audit event.")
|
||||
s.logger.Errorf("Failed to write audit event: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/sshlog"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const SSHPreambleLength = 2
|
||||
|
@ -20,7 +20,7 @@ type SSHPreamble struct {
|
|||
JWT string
|
||||
}
|
||||
|
||||
func New(_ sshlog.Manager, _ *logrus.Logger, _, _, _, _ string, _ chan struct{}, _, _ time.Duration) (*SSHServer, error) {
|
||||
func New(_ sshlog.Manager, _ logger.Service, _, _, _, _ string, _ chan struct{}, _, _ time.Duration) (*SSHServer, error) {
|
||||
return nil, errors.New("cloudflared ssh server is not supported on windows")
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/tunnelhostnamemapper"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"zombiezen.com/go/capnproto2/rpc"
|
||||
)
|
||||
|
||||
|
@ -45,19 +45,19 @@ type StreamHandler struct {
|
|||
useConfigResultChan <-chan *pogs.UseConfigurationResult
|
||||
// originMapper maps tunnel hostname to origin service
|
||||
tunnelHostnameMapper *tunnelhostnamemapper.TunnelHostnameMapper
|
||||
logger *logrus.Entry
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
// NewStreamHandler creates a new StreamHandler
|
||||
func NewStreamHandler(newConfigChan chan<- *pogs.ClientConfig,
|
||||
useConfigResultChan <-chan *pogs.UseConfigurationResult,
|
||||
logger *logrus.Logger,
|
||||
logger logger.Service,
|
||||
) *StreamHandler {
|
||||
return &StreamHandler{
|
||||
newConfigChan: newConfigChan,
|
||||
useConfigResultChan: useConfigResultChan,
|
||||
tunnelHostnameMapper: tunnelhostnamemapper.NewTunnelHostnameMapper(),
|
||||
logger: logger.WithField("subsystem", "streamHandler"),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,14 +66,14 @@ func (s *StreamHandler) UseConfiguration(ctx context.Context, config *pogs.Clien
|
|||
select {
|
||||
case <-ctx.Done():
|
||||
err := fmt.Errorf("Timeout while sending new config to Supervisor")
|
||||
s.logger.Error(err)
|
||||
s.logger.Errorf("streamHandler: %s", err)
|
||||
return nil, err
|
||||
case s.newConfigChan <- config:
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err := fmt.Errorf("Timeout applying new configuration")
|
||||
s.logger.Error(err)
|
||||
s.logger.Errorf("streamHandler: %s", err)
|
||||
return nil, err
|
||||
case result := <-s.useConfigResultChan:
|
||||
return result, nil
|
||||
|
@ -93,9 +93,9 @@ func (s *StreamHandler) UpdateConfig(newConfig []*pogs.ReverseProxyConfig) (fail
|
|||
toAdd := s.tunnelHostnameMapper.ToAdd(newConfig)
|
||||
for _, tunnelConfig := range toAdd {
|
||||
tunnelHostname := tunnelConfig.TunnelHostname
|
||||
originSerice, err := tunnelConfig.OriginConfig.Service()
|
||||
originSerice, err := tunnelConfig.OriginConfig.Service(s.logger)
|
||||
if err != nil {
|
||||
s.logger.WithField("tunnelHostname", tunnelHostname).WithError(err).Error("Invalid origin service config")
|
||||
s.logger.Errorf("streamHandler: tunnelHostname: %s Invalid origin service config: %s", tunnelHostname, err)
|
||||
failedConfigs = append(failedConfigs, &pogs.FailedConfig{
|
||||
Config: tunnelConfig,
|
||||
Reason: tunnelConfig.FailReason(err),
|
||||
|
@ -103,7 +103,7 @@ func (s *StreamHandler) UpdateConfig(newConfig []*pogs.ReverseProxyConfig) (fail
|
|||
continue
|
||||
}
|
||||
s.tunnelHostnameMapper.Add(tunnelConfig.TunnelHostname, originSerice)
|
||||
s.logger.WithField("tunnelHostname", tunnelHostname).Infof("New origin service config: %v", originSerice.Summary())
|
||||
s.logger.Infof("streamHandler: tunnelHostname: %s New origin service config: %v", tunnelHostname, originSerice.Summary())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ func (s *StreamHandler) ServeStream(stream *h2mux.MuxedStream) error {
|
|||
return s.serveRPC(stream)
|
||||
}
|
||||
if err := s.serveRequest(stream); err != nil {
|
||||
s.logger.Error(err)
|
||||
s.logger.Errorf("streamHandler: %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -123,11 +123,10 @@ func (s *StreamHandler) ServeStream(stream *h2mux.MuxedStream) error {
|
|||
func (s *StreamHandler) serveRPC(stream *h2mux.MuxedStream) error {
|
||||
stream.WriteHeaders([]h2mux.Header{{Name: ":status", Value: "200"}})
|
||||
main := pogs.ClientService_ServerToClient(s)
|
||||
rpcLogger := s.logger.WithField("subsystem", "clientserver-rpc")
|
||||
rpcConn := rpc.NewConn(
|
||||
tunnelrpc.NewTransportLogger(rpcLogger, rpc.StreamTransport(stream)),
|
||||
tunnelrpc.NewTransportLogger(s.logger, rpc.StreamTransport(stream)),
|
||||
rpc.MainInterface(main.Client),
|
||||
tunnelrpc.ConnLog(s.logger.WithField("subsystem", "clientserver-rpc-transport")),
|
||||
tunnelrpc.ConnLog(s.logger),
|
||||
)
|
||||
return rpcConn.Wait()
|
||||
}
|
||||
|
@ -151,8 +150,8 @@ func (s *StreamHandler) serveRequest(stream *h2mux.MuxedStream) error {
|
|||
return errors.Wrap(err, "cannot create request")
|
||||
}
|
||||
|
||||
logger := s.requestLogger(req, tunnelHostname)
|
||||
logger.Debugf("Request Headers %+v", req.Header)
|
||||
cfRay := s.logRequest(req, tunnelHostname)
|
||||
s.logger.Debugf("streamHandler: tunnelHostname: %s CF-RAY: %s Request Headers %+v", tunnelHostname, cfRay, req.Header)
|
||||
|
||||
resp, err := originService.Proxy(stream, req)
|
||||
if err != nil {
|
||||
|
@ -160,23 +159,22 @@ func (s *StreamHandler) serveRequest(stream *h2mux.MuxedStream) error {
|
|||
return errors.Wrap(err, "cannot proxy request")
|
||||
}
|
||||
|
||||
logger.WithField("status", resp.Status).Debugf("Response Headers %+v", resp.Header)
|
||||
s.logger.Debugf("streamHandler: tunnelHostname: %s CF-RAY: %s status: %s Response Headers %+v", tunnelHostname, cfRay, resp.Status, resp.Header)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StreamHandler) requestLogger(req *http.Request, tunnelHostname h2mux.TunnelHostname) *logrus.Entry {
|
||||
func (s *StreamHandler) logRequest(req *http.Request, tunnelHostname h2mux.TunnelHostname) string {
|
||||
cfRay := FindCfRayHeader(req)
|
||||
lbProbe := IsLBProbeRequest(req)
|
||||
logger := s.logger.WithField("tunnelHostname", tunnelHostname)
|
||||
logger := s.logger
|
||||
if cfRay != "" {
|
||||
logger = logger.WithField("CF-RAY", cfRay)
|
||||
logger.Debugf("%s %s %s", req.Method, req.URL, req.Proto)
|
||||
logger.Debugf("streamHandler: tunnelHostname: %s CF-RAY: %s %s %s %s", tunnelHostname, cfRay, req.Method, req.URL, req.Proto)
|
||||
} else if lbProbe {
|
||||
logger.Debugf("Load Balancer health check %s %s %s", req.Method, req.URL, req.Proto)
|
||||
logger.Debugf("streamHandler: tunnelHostname: %s CF-RAY: %s Load Balancer health check %s %s %s", tunnelHostname, cfRay, req.Method, req.URL, req.Proto)
|
||||
} else {
|
||||
logger.Warnf("Requests %v does not have CF-RAY header. Please open a support ticket with Cloudflare.", req)
|
||||
logger.Infof("streamHandler: tunnelHostname: %s CF-RAY: %s Requests %v does not have CF-RAY header. Please open a support ticket with Cloudflare.", tunnelHostname, cfRay, req)
|
||||
}
|
||||
return logger
|
||||
return cfRay
|
||||
}
|
||||
|
||||
func (s *StreamHandler) writeErrorStatus(stream *h2mux.MuxedStream, status *httpErrorStatus) {
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
@ -39,9 +39,10 @@ var (
|
|||
)
|
||||
|
||||
func TestServeRequest(t *testing.T) {
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
configChan := make(chan *pogs.ClientConfig)
|
||||
useConfigResultChan := make(chan *pogs.UseConfigurationResult)
|
||||
streamHandler := NewStreamHandler(configChan, useConfigResultChan, logrus.New())
|
||||
streamHandler := NewStreamHandler(configChan, useConfigResultChan, l)
|
||||
|
||||
message := []byte("Hello cloudflared")
|
||||
httpServer := httptest.NewServer(&mockHTTPHandler{message})
|
||||
|
@ -72,8 +73,9 @@ func TestServeRequest(t *testing.T) {
|
|||
func createStreamHandler() *StreamHandler {
|
||||
configChan := make(chan *pogs.ClientConfig)
|
||||
useConfigResultChan := make(chan *pogs.UseConfigurationResult)
|
||||
l := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
return NewStreamHandler(configChan, useConfigResultChan, logrus.New())
|
||||
return NewStreamHandler(configChan, useConfigResultChan, l)
|
||||
}
|
||||
|
||||
func createRequestMuxPair(t *testing.T, streamHandler *StreamHandler) *DefaultMuxerPair {
|
||||
|
@ -185,7 +187,7 @@ func NewDefaultMuxerPair(t *testing.T, h h2mux.MuxedStreamHandler) *DefaultMuxer
|
|||
Handler: h,
|
||||
IsClient: true,
|
||||
Name: "origin",
|
||||
Logger: logrus.NewEntry(logrus.New()),
|
||||
Logger: logger.NewOutputWriter(logger.NewMockWriteManager()),
|
||||
DefaultWindowSize: (1 << 8) - 1,
|
||||
MaxWindowSize: (1 << 15) - 1,
|
||||
StreamWriteBufferMaxLen: 1024,
|
||||
|
@ -195,7 +197,7 @@ func NewDefaultMuxerPair(t *testing.T, h h2mux.MuxedStreamHandler) *DefaultMuxer
|
|||
Timeout: testHandshakeTimeout,
|
||||
IsClient: false,
|
||||
Name: "edge",
|
||||
Logger: logrus.NewEntry(logrus.New()),
|
||||
Logger: logger.NewOutputWriter(logger.NewMockWriteManager()),
|
||||
DefaultWindowSize: (1 << 8) - 1,
|
||||
MaxWindowSize: (1 << 15) - 1,
|
||||
StreamWriteBufferMaxLen: 1024,
|
||||
|
|
|
@ -16,10 +16,10 @@ import (
|
|||
"github.com/cloudflare/cloudflared/connection"
|
||||
"github.com/cloudflare/cloudflared/edgediscovery"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/streamhandler"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Supervisor struct {
|
||||
|
@ -30,7 +30,7 @@ type Supervisor struct {
|
|||
newConfigChan <-chan *pogs.ClientConfig
|
||||
useConfigResultChan chan<- *pogs.UseConfigurationResult
|
||||
state *state
|
||||
logger *logrus.Entry
|
||||
logger logger.Service
|
||||
metrics metrics
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ func NewSupervisor(
|
|||
cloudflaredConfig *connection.CloudflaredConfig,
|
||||
autoupdater *updater.AutoUpdater,
|
||||
supportAutoupdate bool,
|
||||
logger *logrus.Logger,
|
||||
logger logger.Service,
|
||||
) (*Supervisor, error) {
|
||||
newConfigChan := make(chan *pogs.ClientConfig)
|
||||
useConfigResultChan := make(chan *pogs.UseConfigurationResult)
|
||||
|
@ -93,7 +93,7 @@ func NewSupervisor(
|
|||
newConfigChan: newConfigChan,
|
||||
useConfigResultChan: useConfigResultChan,
|
||||
state: newState(defaultClientConfig),
|
||||
logger: logger.WithField("subsystem", "supervisor"),
|
||||
logger: logger,
|
||||
metrics: newMetrics(),
|
||||
}, nil
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func (s *Supervisor) Run(ctx context.Context) error {
|
|||
}
|
||||
|
||||
err := errGroup.Wait()
|
||||
s.logger.Warnf("Supervisor terminated, reason: %v", err)
|
||||
s.logger.Errorf("Supervisor terminated, reason: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/getsentry/raven-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
|
@ -65,7 +65,7 @@ func (cr *CertReloader) LoadCert() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func LoadOriginCA(c *cli.Context, logger *logrus.Logger) (*x509.CertPool, error) {
|
||||
func LoadOriginCA(c *cli.Context, logger logger.Service) (*x509.CertPool, error) {
|
||||
var originCustomCAPool []byte
|
||||
|
||||
originCAPoolFilename := c.String(OriginCAPoolFlag)
|
||||
|
@ -151,7 +151,7 @@ func CreateTunnelConfig(c *cli.Context) (*tls.Config, error) {
|
|||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
func loadOriginCertPool(originCAPoolPEM []byte, logger *logrus.Logger) (*x509.CertPool, error) {
|
||||
func loadOriginCertPool(originCAPoolPEM []byte, logger logger.Service) (*x509.CertPool, error) {
|
||||
// Get the global pool
|
||||
certPool, err := loadGlobalCertPool(logger)
|
||||
if err != nil {
|
||||
|
@ -161,19 +161,19 @@ func loadOriginCertPool(originCAPoolPEM []byte, logger *logrus.Logger) (*x509.Ce
|
|||
// Then, add any custom origin CA pool the user may have passed
|
||||
if originCAPoolPEM != nil {
|
||||
if !certPool.AppendCertsFromPEM(originCAPoolPEM) {
|
||||
logger.Warn("could not append the provided origin CA to the cloudflared certificate pool")
|
||||
logger.Info("could not append the provided origin CA to the cloudflared certificate pool")
|
||||
}
|
||||
}
|
||||
|
||||
return certPool, nil
|
||||
}
|
||||
|
||||
func loadGlobalCertPool(logger *logrus.Logger) (*x509.CertPool, error) {
|
||||
func loadGlobalCertPool(logger logger.Service) (*x509.CertPool, error) {
|
||||
// First, obtain the system certificate pool
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
if runtime.GOOS != "windows" { // See https://github.com/golang/go/issues/16736
|
||||
logger.WithError(err).Warn("error obtaining the system certificates")
|
||||
logger.Infof("error obtaining the system certificates: %s", err)
|
||||
}
|
||||
certPool = x509.NewCertPool()
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
|
@ -26,15 +26,16 @@ type UpstreamHTTPS struct {
|
|||
client *http.Client
|
||||
endpoint *url.URL
|
||||
bootstraps []string
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
// NewUpstreamHTTPS creates a new DNS over HTTPS upstream from endpoint
|
||||
func NewUpstreamHTTPS(endpoint string, bootstraps []string) (Upstream, error) {
|
||||
func NewUpstreamHTTPS(endpoint string, bootstraps []string, logger logger.Service) (Upstream, error) {
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UpstreamHTTPS{client: configureClient(u.Hostname()), endpoint: u, bootstraps: bootstraps}, nil
|
||||
return &UpstreamHTTPS{client: configureClient(u.Hostname()), endpoint: u, bootstraps: bootstraps, logger: logger}, nil
|
||||
}
|
||||
|
||||
// Exchange provides an implementation for the Upstream interface
|
||||
|
@ -48,12 +49,12 @@ func (u *UpstreamHTTPS) Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg,
|
|||
for _, bootstrap := range u.bootstraps {
|
||||
endpoint, client, err := configureBootstrap(bootstrap)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("failed to configure boostrap upstream %s", bootstrap)
|
||||
u.logger.Errorf("failed to configure boostrap upstream %s: %s", bootstrap, err)
|
||||
continue
|
||||
}
|
||||
msg, err := exchange(queryBuf, query.Id, endpoint, client)
|
||||
msg, err := exchange(queryBuf, query.Id, endpoint, client, u.logger)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("failed to connect to a boostrap upstream %s", bootstrap)
|
||||
u.logger.Errorf("failed to connect to a boostrap upstream %s: %s", bootstrap, err)
|
||||
continue
|
||||
}
|
||||
return msg, nil
|
||||
|
@ -61,10 +62,10 @@ func (u *UpstreamHTTPS) Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg,
|
|||
return nil, fmt.Errorf("failed to reach any bootstrap upstream: %v", u.bootstraps)
|
||||
}
|
||||
|
||||
return exchange(queryBuf, query.Id, u.endpoint, u.client)
|
||||
return exchange(queryBuf, query.Id, u.endpoint, u.client, u.logger)
|
||||
}
|
||||
|
||||
func exchange(msg []byte, queryID uint16, endpoint *url.URL, client *http.Client) (*dns.Msg, error) {
|
||||
func exchange(msg []byte, queryID uint16, endpoint *url.URL, client *http.Client, logger logger.Service) (*dns.Msg, error) {
|
||||
// No content negotiation for now, use DNS wire format
|
||||
buf, backendErr := exchangeWireformat(msg, endpoint, client)
|
||||
if backendErr == nil {
|
||||
|
@ -77,7 +78,7 @@ func exchange(msg []byte, queryID uint16, endpoint *url.URL, client *http.Client
|
|||
return response, nil
|
||||
}
|
||||
|
||||
log.WithError(backendErr).Errorf("failed to connect to an HTTPS backend %q", endpoint)
|
||||
logger.Errorf("failed to connect to an HTTPS backend %q: %s", endpoint, backendErr)
|
||||
return nil, backendErr
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ import (
|
|||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/cloudflare/cloudflared/log"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/metrics"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
|
@ -18,26 +19,31 @@ import (
|
|||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
var logger = log.CreateLogger()
|
||||
|
||||
// Listener is an adapter between CoreDNS server and Warp runnable
|
||||
type Listener struct {
|
||||
server *dnsserver.Server
|
||||
wg sync.WaitGroup
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
// Run implements a foreground runner
|
||||
func Run(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")
|
||||
}
|
||||
|
||||
metricsListener, err := net.Listen("tcp", c.String("metrics"))
|
||||
if err != nil {
|
||||
logger.WithError(err).Fatal("Failed to open the metrics listener")
|
||||
logger.Fatalf("Failed to open the metrics listener: %s", err)
|
||||
}
|
||||
|
||||
go metrics.ServeMetrics(metricsListener, nil, logger)
|
||||
|
||||
listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream"), c.StringSlice("bootstrap"))
|
||||
listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream"), c.StringSlice("bootstrap"), logger)
|
||||
if err != nil {
|
||||
logger.WithError(err).Errorf("Failed to create the listeners")
|
||||
logger.Errorf("Failed to create the listeners: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -45,7 +51,7 @@ func Run(c *cli.Context) error {
|
|||
readySignal := make(chan struct{})
|
||||
err = listener.Start(readySignal)
|
||||
if err != nil {
|
||||
logger.WithError(err).Errorf("Failed to start the listeners")
|
||||
logger.Errorf("Failed to start the listeners: %s", err)
|
||||
return listener.Stop()
|
||||
}
|
||||
<-readySignal
|
||||
|
@ -59,7 +65,7 @@ func Run(c *cli.Context) error {
|
|||
// Shut down server
|
||||
err = listener.Stop()
|
||||
if err != nil {
|
||||
logger.WithError(err).Errorf("failed to stop")
|
||||
logger.Errorf("failed to stop: %s", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -80,7 +86,7 @@ func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Conf
|
|||
// Start blocks for serving requests
|
||||
func (l *Listener) Start(readySignal chan struct{}) error {
|
||||
defer close(readySignal)
|
||||
logger.WithField("addr", l.server.Address()).Infof("Starting DNS over HTTPS proxy server")
|
||||
l.logger.Infof("Starting DNS over HTTPS proxy server on: %s", l.server.Address())
|
||||
|
||||
// Start UDP listener
|
||||
if udp, err := l.server.ListenPacket(); err == nil {
|
||||
|
@ -117,12 +123,12 @@ func (l *Listener) Stop() error {
|
|||
}
|
||||
|
||||
// CreateListener configures the server and bound sockets
|
||||
func CreateListener(address string, port uint16, upstreams []string, bootstraps []string) (*Listener, error) {
|
||||
func CreateListener(address string, port uint16, upstreams []string, bootstraps []string, logger logger.Service) (*Listener, error) {
|
||||
// Build the list of upstreams
|
||||
upstreamList := make([]Upstream, 0)
|
||||
for _, url := range upstreams {
|
||||
logger.WithField("url", url).Infof("Adding DNS upstream")
|
||||
upstream, err := NewUpstreamHTTPS(url, bootstraps)
|
||||
logger.Infof("Adding DNS upstream - url: %s", url)
|
||||
upstream, err := NewUpstreamHTTPS(url, bootstraps, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create HTTPS upstream")
|
||||
}
|
||||
|
@ -144,5 +150,5 @@ func CreateListener(address string, port uint16, upstreams []string, bootstraps
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &Listener{server: server}, nil
|
||||
return &Listener{server: server, logger: logger}, nil
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ package tunnelrpc
|
|||
import (
|
||||
"context"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"golang.org/x/net/trace"
|
||||
"zombiezen.com/go/capnproto2/rpc"
|
||||
)
|
||||
|
||||
// ConnLogger wraps a logrus *log.Entry for a connection.
|
||||
type ConnLogger struct {
|
||||
Entry *log.Entry
|
||||
Entry logger.Service
|
||||
}
|
||||
|
||||
func (c ConnLogger) Infof(ctx context.Context, format string, args ...interface{}) {
|
||||
|
@ -21,7 +21,7 @@ func (c ConnLogger) Errorf(ctx context.Context, format string, args ...interface
|
|||
c.Entry.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func ConnLog(log *log.Entry) rpc.ConnOption {
|
||||
func ConnLog(log logger.Service) rpc.ConnOption {
|
||||
return rpc.ConnLog(ConnLogger{log})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"zombiezen.com/go/capnproto2/encoding/text"
|
||||
"zombiezen.com/go/capnproto2/rpc"
|
||||
rpccapnp "zombiezen.com/go/capnproto2/std/capnp/rpc"
|
||||
|
@ -13,28 +13,28 @@ import (
|
|||
|
||||
type transport struct {
|
||||
rpc.Transport
|
||||
l *log.Entry
|
||||
l logger.Service
|
||||
}
|
||||
|
||||
// New creates a new logger that proxies messages to and from t and
|
||||
// NewTransportLogger creates a new logger that proxies messages to and from t and
|
||||
// logs them to l. If l is nil, then the log package's default
|
||||
// logger is used.
|
||||
func NewTransportLogger(l *log.Entry, t rpc.Transport) rpc.Transport {
|
||||
func NewTransportLogger(l logger.Service, t rpc.Transport) rpc.Transport {
|
||||
return &transport{Transport: t, l: l}
|
||||
}
|
||||
|
||||
func (t *transport) SendMessage(ctx context.Context, msg rpccapnp.Message) error {
|
||||
t.l.Debugf("tx %s", formatMsg(msg))
|
||||
t.l.Debugf("rpcconnect: tx %s", formatMsg(msg))
|
||||
return t.Transport.SendMessage(ctx, msg)
|
||||
}
|
||||
|
||||
func (t *transport) RecvMessage(ctx context.Context) (rpccapnp.Message, error) {
|
||||
msg, err := t.Transport.RecvMessage(ctx)
|
||||
if err != nil {
|
||||
t.l.WithError(err).Debug("rx error")
|
||||
t.l.Debugf("rpcconnect: rx error: %s", err)
|
||||
return msg, err
|
||||
}
|
||||
t.l.Debugf("rx %s", formatMsg(msg))
|
||||
t.l.Debugf("rpcconnect: rx %s", formatMsg(msg))
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/originservice"
|
||||
"github.com/cloudflare/cloudflared/tlsconfig"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
|
@ -171,7 +172,7 @@ func (_ *ReverseProxyConfig) isFallibleConfig() {}
|
|||
//go-sumtype:decl OriginConfig
|
||||
type OriginConfig interface {
|
||||
// Service returns a OriginService used to proxy to the origin
|
||||
Service() (originservice.OriginService, error)
|
||||
Service(logger.Service) (originservice.OriginService, error)
|
||||
// go-sumtype requires at least one unexported method, otherwise it will complain that interface is not sealed
|
||||
isOriginConfig()
|
||||
}
|
||||
|
@ -191,7 +192,7 @@ type HTTPOriginConfig struct {
|
|||
ChunkedEncoding bool
|
||||
}
|
||||
|
||||
func (hc *HTTPOriginConfig) Service() (originservice.OriginService, error) {
|
||||
func (hc *HTTPOriginConfig) Service(logger logger.Service) (originservice.OriginService, error) {
|
||||
rootCAs, err := tlsconfig.LoadCustomOriginCA(hc.OriginCAPool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -239,7 +240,7 @@ type WebSocketOriginConfig struct {
|
|||
OriginServerName string
|
||||
}
|
||||
|
||||
func (wsc *WebSocketOriginConfig) Service() (originservice.OriginService, error) {
|
||||
func (wsc *WebSocketOriginConfig) Service(logger logger.Service) (originservice.OriginService, error) {
|
||||
rootCAs, err := tlsconfig.LoadCustomOriginCA(wsc.OriginCAPool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -254,14 +255,14 @@ func (wsc *WebSocketOriginConfig) Service() (originservice.OriginService, error)
|
|||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "%s is not a valid URL", wsc.URLString)
|
||||
}
|
||||
return originservice.NewWebSocketService(tlsConfig, url)
|
||||
return originservice.NewWebSocketService(tlsConfig, url, logger)
|
||||
}
|
||||
|
||||
func (*WebSocketOriginConfig) isOriginConfig() {}
|
||||
|
||||
type HelloWorldOriginConfig struct{}
|
||||
|
||||
func (*HelloWorldOriginConfig) Service() (originservice.OriginService, error) {
|
||||
func (*HelloWorldOriginConfig) Service(logger logger.Service) (originservice.OriginService, error) {
|
||||
helloCert, err := tlsconfig.GetHelloCertificateX509()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Cannot get Hello World server certificate")
|
||||
|
@ -282,7 +283,7 @@ func (*HelloWorldOriginConfig) Service() (originservice.OriginService, error) {
|
|||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
return originservice.NewHelloWorldService(transport)
|
||||
return originservice.NewHelloWorldService(transport, logger)
|
||||
}
|
||||
|
||||
func (*HelloWorldOriginConfig) isOriginConfig() {}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
capnp "zombiezen.com/go/capnproto2"
|
||||
)
|
||||
|
@ -241,9 +242,10 @@ func TestOriginConfigInvalidURL(t *testing.T) {
|
|||
URLString: "127.0.0.1:36192",
|
||||
},
|
||||
}
|
||||
logger := logger.NewOutputWriter(logger.NewMockWriteManager())
|
||||
|
||||
for _, config := range invalidConfigs {
|
||||
service, err := config.Service()
|
||||
service, err := config.Service(logger)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, service)
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -42,11 +42,12 @@ type RESTClient struct {
|
|||
baseURL string
|
||||
authToken string
|
||||
client http.Client
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
var _ Client = (*RESTClient)(nil)
|
||||
|
||||
func NewRESTClient(baseURL string, accountTag string, authToken string) *RESTClient {
|
||||
func NewRESTClient(baseURL string, accountTag string, authToken string, logger logger.Service) *RESTClient {
|
||||
if strings.HasSuffix(baseURL, "/") {
|
||||
baseURL = baseURL[:len(baseURL)-1]
|
||||
}
|
||||
|
@ -61,6 +62,7 @@ func NewRESTClient(baseURL string, accountTag string, authToken string) *RESTCli
|
|||
},
|
||||
Timeout: defaultTimeout,
|
||||
},
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +148,7 @@ func (r *RESTClient) resolve(target string) string {
|
|||
|
||||
func (r *RESTClient) sendRequest(method string, target string, body io.Reader) (*http.Response, error) {
|
||||
url := r.resolve(target)
|
||||
logrus.Debugf("%s %s", method, url)
|
||||
r.logger.Debugf("%s %s", method, url)
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't create %s request", method)
|
||||
|
@ -180,5 +182,3 @@ func statusCodeToError(op string, resp *http.Response) error {
|
|||
return errors.Errorf("API call to %s tunnel failed with status %d: %s", op,
|
||||
resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||
Copyright (c) 2016 Austin Cherry
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
|
@ -0,0 +1,40 @@
|
|||
Skittles
|
||||
========
|
||||
|
||||
Miminal package for terminal colors/ANSI escape code.
|
||||
|
||||
![alt tag](https://raw.githubusercontent.com/acmacalister/skittles/master/pictures/terminal-colors.png)
|
||||
|
||||
## Install
|
||||
|
||||
`go get github.com/acmacalister/skittles`
|
||||
|
||||
`import "github.com/acmacalister/skittles"`
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/acmacalister/skittles"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(skittles.Red("Red's my favorite color"))
|
||||
}
|
||||
```
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
Only tested on OS X terminal app, but I would expect it to work with any unix based terminal.
|
||||
|
||||
## Docs
|
||||
|
||||
* [GoDoc](http://godoc.org/github.com/acmacalister/skittles)
|
||||
|
||||
## Help
|
||||
|
||||
* [Github](https://github.com/acmacalister)
|
||||
* [Twitter](http://twitter.com/acmacalister)
|
|
@ -0,0 +1,153 @@
|
|||
// Miminal package for terminal colors/ANSI escape code.
|
||||
// Check out the source here https://github.com/acmacalister/skittles.
|
||||
// Also see the example directory for another example on how to use skittles.
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "fmt"
|
||||
// "github.com/acmacalister/skittles"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// fmt.Println(skittles.Red("Red's my favorite color"))
|
||||
// }
|
||||
package skittles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// source: http://www.termsys.demon.co.uk/vtansi.htm
|
||||
// source: http://ascii-table.com/ansi-escape-sequences.php
|
||||
|
||||
const (
|
||||
nofmt = "0"
|
||||
bold = "1"
|
||||
underline = "4"
|
||||
blink = "5"
|
||||
inverse = "7" // attributes end at 7
|
||||
black = "30" // colors start at 30
|
||||
red = "31"
|
||||
green = "32"
|
||||
yellow = "33"
|
||||
blue = "34"
|
||||
magenta = "35"
|
||||
cyan = "36"
|
||||
white = "37" // colors end at 37
|
||||
blackBackground = "40" // background colors start at 40
|
||||
redBackground = "41"
|
||||
greenBackground = "42"
|
||||
yellowBackground = "43"
|
||||
blueBackground = "44"
|
||||
magentaBackground = "45"
|
||||
cyanBackground = "46"
|
||||
whiteBackground = "47"
|
||||
)
|
||||
|
||||
// makeFunction returns a function that formats some text with the provided list
|
||||
// of ANSI escape codes.
|
||||
func makeFunction(attributes []string) func(interface{}) string {
|
||||
return func(text interface{}) string {
|
||||
return fmt.Sprintf("\033[%sm%s\033[0m", strings.Join(attributes, ";"), text)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// Reset resets all formatting.
|
||||
Reset = makeFunction([]string{nofmt})
|
||||
// Bold makes terminal text bold and doesn't add any color.
|
||||
Bold = makeFunction([]string{bold})
|
||||
// Underline makes terminal text underlined and doesn't add any color.
|
||||
Underline = makeFunction([]string{underline})
|
||||
// Blink makes terminal text blink and doesn't add any color.
|
||||
Blink = makeFunction([]string{blink})
|
||||
// Inverse inverts terminal text and doesn't add any color.
|
||||
Inverse = makeFunction([]string{inverse})
|
||||
|
||||
// Black makes terminal text black.
|
||||
Black = makeFunction([]string{black})
|
||||
// Red makes terminal text red.
|
||||
Red = makeFunction([]string{red})
|
||||
// Green makes terminal text green.
|
||||
Green = makeFunction([]string{green})
|
||||
// Yellow makes terminal text yellow.
|
||||
Yellow = makeFunction([]string{yellow})
|
||||
// Blue makes terminal text blue.
|
||||
Blue = makeFunction([]string{blue})
|
||||
// Magenta makes terminal text magenta.
|
||||
Magenta = makeFunction([]string{magenta})
|
||||
// Cyan makes terminal text cyan.
|
||||
Cyan = makeFunction([]string{cyan})
|
||||
// White makes terminal text white.
|
||||
White = makeFunction([]string{white})
|
||||
|
||||
// BoldBlack makes terminal text bold and black.
|
||||
BoldBlack = makeFunction([]string{black, bold})
|
||||
// BoldRed makes terminal text bold and red.
|
||||
BoldRed = makeFunction([]string{red, bold})
|
||||
// BoldGreen makes terminal text bold and green.
|
||||
BoldGreen = makeFunction([]string{green, bold})
|
||||
// BoldYellow makes terminal text bold and yellow.
|
||||
BoldYellow = makeFunction([]string{yellow, bold})
|
||||
// BoldBlue makes terminal text bold and blue.
|
||||
BoldBlue = makeFunction([]string{blue, bold})
|
||||
// BoldMagenta makes terminal text bold and magenta.
|
||||
BoldMagenta = makeFunction([]string{magenta, bold})
|
||||
// BoldCyan makes terminal text bold and cyan.
|
||||
BoldCyan = makeFunction([]string{cyan, bold})
|
||||
// BoldWhite makes terminal text bold and white.
|
||||
BoldWhite = makeFunction([]string{white, bold})
|
||||
|
||||
// BlinkBlack makes terminal text blink and black.
|
||||
BlinkBlack = makeFunction([]string{black, blink})
|
||||
// BlinkRed makes terminal text blink and red.
|
||||
BlinkRed = makeFunction([]string{red, blink})
|
||||
// BlinkGreen makes terminal text blink and green.
|
||||
BlinkGreen = makeFunction([]string{green, blink})
|
||||
// BlinkYellow makes terminal text blink and yellow.
|
||||
BlinkYellow = makeFunction([]string{yellow, blink})
|
||||
// BlinkBlue makes terminal text blink and blue.
|
||||
BlinkBlue = makeFunction([]string{blue, blink})
|
||||
// BlinkMagenta makes terminal text blink and magenta.
|
||||
BlinkMagenta = makeFunction([]string{magenta, blink})
|
||||
// BlinkCyan makes terminal text blink and cyan.
|
||||
BlinkCyan = makeFunction([]string{cyan, blink})
|
||||
// BlinkWhite makes terminal text blink and white.
|
||||
BlinkWhite = makeFunction([]string{white, blink})
|
||||
|
||||
// UnderlineBlack makes terminal text underlined and black.
|
||||
UnderlineBlack = makeFunction([]string{black, underline})
|
||||
// UnderlineRed makes terminal text underlined and red.
|
||||
UnderlineRed = makeFunction([]string{red, underline})
|
||||
// UnderlineGreen makes terminal text underlined and green.
|
||||
UnderlineGreen = makeFunction([]string{green, underline})
|
||||
// UnderlineYellow makes terminal text underlined and yellow.
|
||||
UnderlineYellow = makeFunction([]string{yellow, underline})
|
||||
// UnderlineBlue makes terminal text underlined and blue.
|
||||
UnderlineBlue = makeFunction([]string{blue, underline})
|
||||
// UnderlineMagenta makes terminal text underlined and magenta.
|
||||
UnderlineMagenta = makeFunction([]string{magenta, underline})
|
||||
// UnderlineCyan makes terminal text underlined and cyan.
|
||||
UnderlineCyan = makeFunction([]string{cyan, underline})
|
||||
// UnderlineWhite makes terminal text underlined and white.
|
||||
UnderlineWhite = makeFunction([]string{white, underline})
|
||||
|
||||
// InverseBlack makes terminal text inverted and black.
|
||||
InverseBlack = makeFunction([]string{black, inverse})
|
||||
// InverseRed makes terminal text inverted and red.
|
||||
InverseRed = makeFunction([]string{red, inverse})
|
||||
// InverseGreen makes terminal text inverted and green.
|
||||
InverseGreen = makeFunction([]string{green, inverse})
|
||||
// InverseYellow makes terminal text inverted and yellow.
|
||||
InverseYellow = makeFunction([]string{yellow, inverse})
|
||||
// InverseBlue makes terminal text inverted and blue.
|
||||
InverseBlue = makeFunction([]string{blue, inverse})
|
||||
// InverseMagenta makes terminal text inverted and magenta.
|
||||
InverseMagenta = makeFunction([]string{magenta, inverse})
|
||||
// InverseCyan makes terminal text inverted and cyan.
|
||||
InverseCyan = makeFunction([]string{cyan, inverse})
|
||||
// InverseWhite makes terminal text inverted and white.
|
||||
InverseWhite = makeFunction([]string{white, inverse})
|
||||
)
|
24
vendor/github.com/rifflock/lfshook/LICENSE → vendor/github.com/alecthomas/units/COPYING
generated
vendored
24
vendor/github.com/rifflock/lfshook/LICENSE → vendor/github.com/alecthomas/units/COPYING
generated
vendored
|
@ -1,21 +1,19 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (C) 2014 Alec Thomas
|
||||
|
||||
Copyright (c) 2015 Michael Riffle
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,11 @@
|
|||
# Units - Helpful unit multipliers and functions for Go
|
||||
|
||||
The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package.
|
||||
|
||||
It allows for code like this:
|
||||
|
||||
```go
|
||||
n, err := ParseBase2Bytes("1KB")
|
||||
// n == 1024
|
||||
n = units.Mebibyte * 512
|
||||
```
|
|
@ -0,0 +1,83 @@
|
|||
package units
|
||||
|
||||
// Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte,
|
||||
// etc.).
|
||||
type Base2Bytes int64
|
||||
|
||||
// Base-2 byte units.
|
||||
const (
|
||||
Kibibyte Base2Bytes = 1024
|
||||
KiB = Kibibyte
|
||||
Mebibyte = Kibibyte * 1024
|
||||
MiB = Mebibyte
|
||||
Gibibyte = Mebibyte * 1024
|
||||
GiB = Gibibyte
|
||||
Tebibyte = Gibibyte * 1024
|
||||
TiB = Tebibyte
|
||||
Pebibyte = Tebibyte * 1024
|
||||
PiB = Pebibyte
|
||||
Exbibyte = Pebibyte * 1024
|
||||
EiB = Exbibyte
|
||||
)
|
||||
|
||||
var (
|
||||
bytesUnitMap = MakeUnitMap("iB", "B", 1024)
|
||||
oldBytesUnitMap = MakeUnitMap("B", "B", 1024)
|
||||
)
|
||||
|
||||
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
||||
// and KiB are both 1024.
|
||||
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
||||
n, err := ParseUnit(s, bytesUnitMap)
|
||||
if err != nil {
|
||||
n, err = ParseUnit(s, oldBytesUnitMap)
|
||||
}
|
||||
return Base2Bytes(n), err
|
||||
}
|
||||
|
||||
func (b Base2Bytes) String() string {
|
||||
return ToString(int64(b), 1024, "iB", "B")
|
||||
}
|
||||
|
||||
var (
|
||||
metricBytesUnitMap = MakeUnitMap("B", "B", 1000)
|
||||
)
|
||||
|
||||
// MetricBytes are SI byte units (1000 bytes in a kilobyte).
|
||||
type MetricBytes SI
|
||||
|
||||
// SI base-10 byte units.
|
||||
const (
|
||||
Kilobyte MetricBytes = 1000
|
||||
KB = Kilobyte
|
||||
Megabyte = Kilobyte * 1000
|
||||
MB = Megabyte
|
||||
Gigabyte = Megabyte * 1000
|
||||
GB = Gigabyte
|
||||
Terabyte = Gigabyte * 1000
|
||||
TB = Terabyte
|
||||
Petabyte = Terabyte * 1000
|
||||
PB = Petabyte
|
||||
Exabyte = Petabyte * 1000
|
||||
EB = Exabyte
|
||||
)
|
||||
|
||||
// ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes.
|
||||
func ParseMetricBytes(s string) (MetricBytes, error) {
|
||||
n, err := ParseUnit(s, metricBytesUnitMap)
|
||||
return MetricBytes(n), err
|
||||
}
|
||||
|
||||
func (m MetricBytes) String() string {
|
||||
return ToString(int64(m), 1000, "B", "B")
|
||||
}
|
||||
|
||||
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
||||
// respectively. That is, KiB represents 1024 and KB represents 1000.
|
||||
func ParseStrictBytes(s string) (int64, error) {
|
||||
n, err := ParseUnit(s, bytesUnitMap)
|
||||
if err != nil {
|
||||
n, err = ParseUnit(s, metricBytesUnitMap)
|
||||
}
|
||||
return int64(n), err
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Package units provides helpful unit multipliers and functions for Go.
|
||||
//
|
||||
// The goal of this package is to have functionality similar to the time [1] package.
|
||||
//
|
||||
//
|
||||
// [1] http://golang.org/pkg/time/
|
||||
//
|
||||
// It allows for code like this:
|
||||
//
|
||||
// n, err := ParseBase2Bytes("1KB")
|
||||
// // n == 1024
|
||||
// n = units.Mebibyte * 512
|
||||
package units
|
|
@ -0,0 +1 @@
|
|||
module github.com/alecthomas/units
|
|
@ -0,0 +1,26 @@
|
|||
package units
|
||||
|
||||
// SI units.
|
||||
type SI int64
|
||||
|
||||
// SI unit multiples.
|
||||
const (
|
||||
Kilo SI = 1000
|
||||
Mega = Kilo * 1000
|
||||
Giga = Mega * 1000
|
||||
Tera = Giga * 1000
|
||||
Peta = Tera * 1000
|
||||
Exa = Peta * 1000
|
||||
)
|
||||
|
||||
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
||||
return map[string]float64{
|
||||
shortSuffix: 1,
|
||||
"K" + suffix: float64(scale),
|
||||
"M" + suffix: float64(scale * scale),
|
||||
"G" + suffix: float64(scale * scale * scale),
|
||||
"T" + suffix: float64(scale * scale * scale * scale),
|
||||
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
||||
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package units
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
siUnits = []string{"", "K", "M", "G", "T", "P", "E"}
|
||||
)
|
||||
|
||||
func ToString(n int64, scale int64, suffix, baseSuffix string) string {
|
||||
mn := len(siUnits)
|
||||
out := make([]string, mn)
|
||||
for i, m := range siUnits {
|
||||
if n%scale != 0 || i == 0 && n == 0 {
|
||||
s := suffix
|
||||
if i == 0 {
|
||||
s = baseSuffix
|
||||
}
|
||||
out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s)
|
||||
}
|
||||
n /= scale
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return strings.Join(out, "")
|
||||
}
|
||||
|
||||
// Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123
|
||||
var errLeadingInt = errors.New("units: bad [0-9]*") // never printed
|
||||
|
||||
// leadingInt consumes the leading [0-9]* from s.
|
||||
func leadingInt(s string) (x int64, rem string, err error) {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
if x >= (1<<63-10)/10 {
|
||||
// overflow
|
||||
return 0, "", errLeadingInt
|
||||
}
|
||||
x = x*10 + int64(c) - '0'
|
||||
}
|
||||
return x, s[i:], nil
|
||||
}
|
||||
|
||||
func ParseUnit(s string, unitMap map[string]float64) (int64, error) {
|
||||
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
|
||||
orig := s
|
||||
f := float64(0)
|
||||
neg := false
|
||||
|
||||
// Consume [-+]?
|
||||
if s != "" {
|
||||
c := s[0]
|
||||
if c == '-' || c == '+' {
|
||||
neg = c == '-'
|
||||
s = s[1:]
|
||||
}
|
||||
}
|
||||
// Special case: if all that is left is "0", this is zero.
|
||||
if s == "0" {
|
||||
return 0, nil
|
||||
}
|
||||
if s == "" {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
for s != "" {
|
||||
g := float64(0) // this element of the sequence
|
||||
|
||||
var x int64
|
||||
var err error
|
||||
|
||||
// The next character must be [0-9.]
|
||||
if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
// Consume [0-9]*
|
||||
pl := len(s)
|
||||
x, s, err = leadingInt(s)
|
||||
if err != nil {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
g = float64(x)
|
||||
pre := pl != len(s) // whether we consumed anything before a period
|
||||
|
||||
// Consume (\.[0-9]*)?
|
||||
post := false
|
||||
if s != "" && s[0] == '.' {
|
||||
s = s[1:]
|
||||
pl := len(s)
|
||||
x, s, err = leadingInt(s)
|
||||
if err != nil {
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
scale := 1.0
|
||||
for n := pl - len(s); n > 0; n-- {
|
||||
scale *= 10
|
||||
}
|
||||
g += float64(x) / scale
|
||||
post = pl != len(s)
|
||||
}
|
||||
if !pre && !post {
|
||||
// no digits (e.g. ".s" or "-.s")
|
||||
return 0, errors.New("units: invalid " + orig)
|
||||
}
|
||||
|
||||
// Consume unit.
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '.' || ('0' <= c && c <= '9') {
|
||||
break
|
||||
}
|
||||
}
|
||||
u := s[:i]
|
||||
s = s[i:]
|
||||
unit, ok := unitMap[u]
|
||||
if !ok {
|
||||
return 0, errors.New("units: unknown unit " + u + " in " + orig)
|
||||
}
|
||||
|
||||
f += g * unit
|
||||
}
|
||||
|
||||
if neg {
|
||||
f = -f
|
||||
}
|
||||
if f < float64(-1<<63) || f > float64(1<<63-1) {
|
||||
return 0, errors.New("units: overflow parsing unit")
|
||||
}
|
||||
return int64(f), nil
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
Copyright (c) 2014 CloudFlare Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,98 +0,0 @@
|
|||
// Package log implements a wrapper around the Go standard library's
|
||||
// logging package. Clients should set the current log level; only
|
||||
// messages below that level will actually be logged. For example, if
|
||||
// Level is set to LevelWarning, only log messages at the Warning,
|
||||
// Error, and Critical levels will be logged.
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
golog "log"
|
||||
)
|
||||
|
||||
// The following constants represent logging levels in increasing levels of seriousness.
|
||||
const (
|
||||
LevelDebug = iota
|
||||
LevelInfo
|
||||
LevelWarning
|
||||
LevelError
|
||||
LevelCritical
|
||||
)
|
||||
|
||||
var levelPrefix = [...]string{
|
||||
LevelDebug: "[DEBUG] ",
|
||||
LevelInfo: "[INFO] ",
|
||||
LevelWarning: "[WARNING] ",
|
||||
LevelError: "[ERROR] ",
|
||||
LevelCritical: "[CRITICAL] ",
|
||||
}
|
||||
|
||||
// Level stores the current logging level.
|
||||
var Level = LevelDebug
|
||||
|
||||
func outputf(l int, format string, v []interface{}) {
|
||||
if l >= Level {
|
||||
golog.Printf(fmt.Sprint(levelPrefix[l], format), v...)
|
||||
}
|
||||
}
|
||||
|
||||
func output(l int, v []interface{}) {
|
||||
if l >= Level {
|
||||
golog.Print(levelPrefix[l], fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Criticalf logs a formatted message at the "critical" level. The
|
||||
// arguments are handled in the same manner as fmt.Printf.
|
||||
func Criticalf(format string, v ...interface{}) {
|
||||
outputf(LevelCritical, format, v)
|
||||
}
|
||||
|
||||
// Critical logs its arguments at the "critical" level.
|
||||
func Critical(v ...interface{}) {
|
||||
output(LevelCritical, v)
|
||||
}
|
||||
|
||||
// Errorf logs a formatted message at the "error" level. The arguments
|
||||
// are handled in the same manner as fmt.Printf.
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
outputf(LevelError, format, v)
|
||||
}
|
||||
|
||||
// Error logs its arguments at the "error" level.
|
||||
func Error(v ...interface{}) {
|
||||
output(LevelError, v)
|
||||
}
|
||||
|
||||
// Warningf logs a formatted message at the "warning" level. The
|
||||
// arguments are handled in the same manner as fmt.Printf.
|
||||
func Warningf(format string, v ...interface{}) {
|
||||
outputf(LevelWarning, format, v)
|
||||
}
|
||||
|
||||
// Warning logs its arguments at the "warning" level.
|
||||
func Warning(v ...interface{}) {
|
||||
output(LevelWarning, v)
|
||||
}
|
||||
|
||||
// Infof logs a formatted message at the "info" level. The arguments
|
||||
// are handled in the same manner as fmt.Printf.
|
||||
func Infof(format string, v ...interface{}) {
|
||||
outputf(LevelInfo, format, v)
|
||||
}
|
||||
|
||||
// Info logs its arguments at the "info" level.
|
||||
func Info(v ...interface{}) {
|
||||
output(LevelInfo, v)
|
||||
}
|
||||
|
||||
// Debugf logs a formatted message at the "debug" level. The arguments
|
||||
// are handled in the same manner as fmt.Printf.
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
outputf(LevelDebug, format, v)
|
||||
}
|
||||
|
||||
// Debug logs its arguments at the "debug" level.
|
||||
func Debug(v ...interface{}) {
|
||||
output(LevelDebug, v)
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
// Package revoke provides functionality for checking the validity of
|
||||
// a cert. Specifically, the temporal validity of the certificate is
|
||||
// checked first, then any CRL in the cert is checked. OCSP is not
|
||||
// supported at this time.
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
neturl "net/url"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// HardFail determines whether the failure to check the revocation
|
||||
// status of a certificate (i.e. due to network failure) causes
|
||||
// verification to fail (a hard failure).
|
||||
var HardFail = false
|
||||
|
||||
// TODO (kyle): figure out a good mechanism for OCSP; this requires
|
||||
// presenting both the certificate and the issuer, and we don't have a
|
||||
// good way at this time of getting the issuer.
|
||||
|
||||
// CRLSet associates a PKIX certificate list with the URL the CRL is
|
||||
// fetched from.
|
||||
var CRLSet = map[string]*pkix.CertificateList{}
|
||||
|
||||
// We can't handle LDAP certificates, so this checks to see if the
|
||||
// URL string points to an LDAP resource so that we can ignore it.
|
||||
func ldapURL(url string) bool {
|
||||
u, err := neturl.Parse(url)
|
||||
if err != nil {
|
||||
log.Warningf("invalid url %s: %v", url, err)
|
||||
return false
|
||||
}
|
||||
if u.Scheme == "ldap" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// revCheck should check the certificate for any revocations. It
|
||||
// returns a pair of booleans: the first indicates whether the certificate
|
||||
// is revoked, the second indicates whether the revocations were
|
||||
// successfully checked.. This leads to the following combinations:
|
||||
//
|
||||
// false, false: an error was encountered while checking revocations.
|
||||
//
|
||||
// false, true: the certificate was checked successfully and
|
||||
// it is not revoked.
|
||||
//
|
||||
// true, true: the certificate was checked successfully and
|
||||
// it is revoked.
|
||||
func revCheck(cert *x509.Certificate) (revoked, ok bool) {
|
||||
for _, url := range cert.CRLDistributionPoints {
|
||||
if ldapURL(url) {
|
||||
log.Infof("skipping LDAP CRL: %s", url)
|
||||
continue
|
||||
}
|
||||
|
||||
if revoked, ok := certIsRevokedCRL(cert, url); !ok {
|
||||
log.Warning("error checking revocation via CRL")
|
||||
if HardFail {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
} else if revoked {
|
||||
log.Info("certificate is revoked via CRL")
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
|
||||
return false, true
|
||||
}
|
||||
|
||||
// fetchCRL fetches and parses a CRL.
|
||||
func fetchCRL(url string) (*pkix.CertificateList, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if resp.StatusCode >= 300 {
|
||||
return nil, errors.New("failed to retrieve CRL")
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return x509.ParseCRL(body)
|
||||
}
|
||||
|
||||
// check a cert against a specific CRL. Returns the same bool pair
|
||||
// as revCheck.
|
||||
func certIsRevokedCRL(cert *x509.Certificate, url string) (revoked, ok bool) {
|
||||
crl, ok := CRLSet[url]
|
||||
if ok && crl == nil {
|
||||
ok = false
|
||||
delete(CRLSet, url)
|
||||
}
|
||||
|
||||
var shouldFetchCRL = true
|
||||
if ok {
|
||||
if !crl.HasExpired(time.Now()) {
|
||||
shouldFetchCRL = false
|
||||
}
|
||||
}
|
||||
|
||||
if shouldFetchCRL {
|
||||
var err error
|
||||
crl, err = fetchCRL(url)
|
||||
if err != nil {
|
||||
log.Warningf("failed to fetch CRL: %v", err)
|
||||
return false, false
|
||||
}
|
||||
CRLSet[url] = crl
|
||||
}
|
||||
|
||||
for _, revoked := range crl.TBSCertList.RevokedCertificates {
|
||||
if cert.SerialNumber.Cmp(revoked.SerialNumber) == 0 {
|
||||
log.Info("Serial number match: intermediate is revoked.")
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
|
||||
return false, true
|
||||
}
|
||||
|
||||
// VerifyCertificate ensures that the certificate passed in hasn't
|
||||
// expired and checks the CRL for the server.
|
||||
func VerifyCertificate(cert *x509.Certificate) (revoked, ok bool) {
|
||||
if !time.Now().Before(cert.NotAfter) {
|
||||
log.Infof("Certificate expired %s\n", cert.NotAfter)
|
||||
return true, true
|
||||
} else if !time.Now().After(cert.NotBefore) {
|
||||
log.Infof("Certificate isn't valid until %s\n", cert.NotBefore)
|
||||
return true, true
|
||||
}
|
||||
|
||||
return revCheck(cert)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue