Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cmd/cloudflared/access/carrier.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/urfave/cli/v2"

"github.com/cloudflare/cloudflared/carrier"
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
cfdflags "github.com/cloudflare/cloudflared/cmd/cloudflared/flags"
"github.com/cloudflare/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/stream"
Expand Down Expand Up @@ -125,6 +127,9 @@ func ssh(c *cli.Context) error {
return errors.Wrap(err, "error validating origin URL")
}
log.Info().Str(LogFieldHost, forwarder.Host).Msg("Start Websocket listener")
if pidfile := c.String(cfdflags.Pidfile); pidfile != "" {
_ = cliutil.WritePidFile(pidfile, log)
}
err = carrier.StartForwarder(wsConn, forwarder.Host, shutdownC, options)
if err != nil {
log.Err(err).Msg("Error on Websocket listener")
Expand All @@ -143,5 +148,8 @@ func ssh(c *cli.Context) error {
logger := log.With().Str("host", url.Host).Logger()
s = stream.NewDebugStream(s, &logger, maxMessages)
}
if pidfile := c.String(cfdflags.Pidfile); pidfile != "" {
_ = cliutil.WritePidFile(pidfile, log)
}
return carrier.StartClient(wsConn, s, options)
}
20 changes: 16 additions & 4 deletions cmd/cloudflared/access/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,17 @@ func Commands() []*cli.Command {
Aliases: []string{"forward"},
Category: "Access",
Usage: "access <subcommand>",
Flags: []cli.Flag{&cli.BoolFlag{
Name: fedrampFlag,
Usage: "use when performing operations in fedramp account",
}},
Flags: []cli.Flag{
&cli.BoolFlag{
Name: fedrampFlag,
Usage: "use when performing operations in fedramp account",
},
&cli.StringFlag{
Name: cfdflags.Pidfile,
Usage: "Write the application's PID to this file after first successful connection.",
EnvVars: []string{"TUNNEL_PIDFILE"},
},
},
Description: `Cloudflare Access protects internal resources by securing, authenticating and monitoring access
per-user and by application. With Cloudflare Access, only authenticated users with the required permissions are
able to reach sensitive resources. The commands provided here allow you to interact with Access protected
Expand Down Expand Up @@ -204,6 +211,11 @@ func Commands() []*cli.Command {
Hidden: true,
Usage: "Writes up-to the max provided stream payloads to the logger as debug statements.",
},
&cli.StringFlag{
Name: cfdflags.Pidfile,
Usage: "Write the application's PID to this file after first successful connection.",
EnvVars: []string{"TUNNEL_PIDFILE"},
},
},
},
{
Expand Down
56 changes: 56 additions & 0 deletions cmd/cloudflared/access/pidfile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package access

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"

cfdflags "github.com/cloudflare/cloudflared/cmd/cloudflared/flags"
)

func TestAccessCommandHasPidfileFlag(t *testing.T) {
t.Parallel()

cmds := Commands()
require.NotEmpty(t, cmds)

var accessCmd *cli.Command
for _, cmd := range cmds {
if cmd.Name == "access" {
accessCmd = cmd
break
}
}
require.NotNil(t, accessCmd)

var accessPidFlag *cli.StringFlag
for _, f := range accessCmd.Flags {
if sf, ok := f.(*cli.StringFlag); ok && sf.Name == cfdflags.Pidfile {
accessPidFlag = sf
break
}
}
require.NotNil(t, accessPidFlag, "access command should have --pidfile flag")
assert.Contains(t, accessPidFlag.EnvVars, "TUNNEL_PIDFILE")

var tcpCmd *cli.Command
for _, sub := range accessCmd.Subcommands {
if sub.Name == "tcp" {
tcpCmd = sub
break
}
}
require.NotNil(t, tcpCmd)

var tcpPidFlag *cli.StringFlag
for _, f := range tcpCmd.Flags {
if sf, ok := f.(*cli.StringFlag); ok && sf.Name == cfdflags.Pidfile {
tcpPidFlag = sf
break
}
}
require.NotNil(t, tcpPidFlag, "access tcp subcommand should have --pidfile flag")
assert.Contains(t, tcpPidFlag.EnvVars, "TUNNEL_PIDFILE")
}
33 changes: 33 additions & 0 deletions cmd/cloudflared/cliutil/pidfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cliutil

import (
"fmt"
"os"
"path/filepath"

"github.com/mitchellh/go-homedir"
"github.com/rs/zerolog"
)

const (
LogFieldPIDPathname = "pidPathname"
LogFieldExpandedPath = "expandedPath"
)

// WritePidFile writes the current process ID into the specified path.
func WritePidFile(pidPathname string, log *zerolog.Logger) error {
expandedPath, err := homedir.Expand(pidPathname)
if err != nil {
log.Err(err).Str(LogFieldPIDPathname, pidPathname).Msg("Unable to expand the path, try to use absolute path in --pidfile")
return err
}
cleanPath := filepath.Clean(expandedPath)
file, err := os.Create(cleanPath)
if err != nil {
log.Err(err).Str(LogFieldExpandedPath, expandedPath).Msg("Unable to write pid")
return err
}
defer func() { _ = file.Close() }()
_, err = fmt.Fprintf(file, "%d", os.Getpid())
return err
}
61 changes: 61 additions & 0 deletions cmd/cloudflared/cliutil/pidfile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cliutil

import (
"os"
"path/filepath"
"strconv"
"strings"
"testing"

"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestWritePidFile_Success(t *testing.T) {
t.Parallel()

tempDir := t.TempDir()
pidPath := filepath.Join(tempDir, "test.pid")
logger := zerolog.Nop()

err := WritePidFile(pidPath, &logger)
require.NoError(t, err)

content, err := os.ReadFile(pidPath)
require.NoError(t, err)

pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
require.NoError(t, err)
assert.Equal(t, os.Getpid(), pid)
}

func TestWritePidFile_InvalidPath(t *testing.T) {
t.Parallel()

// An impossible path where a directory cannot be written into
pidPath := filepath.Join("/nonexistent_dir_12345", "sub", "test.pid")
logger := zerolog.Nop()

err := WritePidFile(pidPath, &logger)
require.Error(t, err)
}

func TestWritePidFile_HomedirExpansion(t *testing.T) {
tempHome := t.TempDir()
t.Setenv("HOME", tempHome)

pidPath := "~/test_homedir.pid"
logger := zerolog.Nop()

err := WritePidFile(pidPath, &logger)
require.NoError(t, err)

expectedPath := filepath.Join(tempHome, "test_homedir.pid")
content, err := os.ReadFile(expectedPath)
require.NoError(t, err)

pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
require.NoError(t, err)
assert.Equal(t, os.Getpid(), pid)
}
3 changes: 3 additions & 0 deletions cmd/cloudflared/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,7 @@ const (

// Automatically close the login interstitial browser window after the user makes a decision.
AutoCloseInterstitial = "auto-close"

// Pidfile writes the application's process ID to a file.
Pidfile = "pidfile"
)
15 changes: 1 addition & 14 deletions cmd/cloudflared/tunnel/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/coreos/go-systemd/v22/daemon"
"github.com/facebookgo/grace/gracenet"
"github.com/getsentry/sentry-go"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -615,19 +614,7 @@ func notifySystemd(waitForSignal *signal.Signal) {

func writePidFile(waitForSignal *signal.Signal, pidPathname string, log *zerolog.Logger) {
<-waitForSignal.Wait()
expandedPath, err := homedir.Expand(pidPathname)
if err != nil {
log.Err(err).Str(LogFieldPIDPathname, pidPathname).Msg("Unable to expand the path, try to use absolute path in --pidfile")
return
}
cleanPath := filepath.Clean(expandedPath)
file, err := os.Create(cleanPath)
if err != nil {
log.Err(err).Str(LogFieldExpandedPath, expandedPath).Msg("Unable to write pid")
return
}
defer func() { _ = file.Close() }()
_, _ = fmt.Fprintf(file, "%d", os.Getpid())
_ = cliutil.WritePidFile(pidPathname, log)
}

func hostnameFromURI(uri string) string {
Expand Down