Compare commits

..

11 Commits

Author SHA1 Message Date
Michael Borkenstein 7260f3e487 Release 2020.7.2 2020-07-13 09:57:36 -05:00
Michael Borkenstein a42b66e8bd AUTH-2872: Adds centos-6 build 2020-07-10 20:39:50 +00:00
Michael Borkenstein 28d556b8d4 AUTH-2858: Set file to disable autoupdate 2020-07-10 18:03:07 +00:00
Areg Harutyunyan 33701f50ec Merge branch 'master' of github.com:cloudflare/cloudflared 2020-07-08 16:35:04 +01:00
Michael Borkenstein abfeebf67d AUTH-2871: fix rpm builds 2020-07-08 14:39:28 +00:00
Sven Höxter 3b293048f4 beautify package meta information generated by fpm (#218)
Current Debian and RPM meta information are very generic, e.g.
$ apt-cache show cloudflared
Package: cloudflared
Version: 2020.7.0
License: unknown
Vendor: @k8s-managed-krwtk.teamcity-agents.svc.cluster.local
Architecture: amd64
Maintainer: <@k8s-managed-krwtk.teamcity-agents.svc.cluster.local>
Installed-Size: 42883
Section: default
Priority: extra
Homepage: http://example.com/no-uri-given
Description: no description given
2020-07-08 15:36:42 +01:00
Igor Postelnik ac3638f6b1 TUN-3169: Move on to the next address when edge returns duplicate connection. There's no point in trying to connect to the same address since it will be hashed to the same metal.
Improve logging of errors from serve tunnel loop, hide useless context cancelled error.
2020-07-07 16:35:44 -05:00
Rachel Williams f7ff41f1dc TUN-3150: cloudflared tunnel list's table should use intelligent column width 2020-07-07 15:48:56 +00:00
cthuang f5c8ff77e9 TUN-3008: Implement cloudflared tunnel cleanup command 2020-07-07 21:56:46 +08:00
cthuang 87e06100df TUN-3131: Allow user to specify tunnel credentials path, and remove it in tunnel delete command 2020-07-07 14:22:08 +08:00
Michael Borkenstein 1ed9e0fceb AUTH-2644: Change install location and add man page 2020-07-06 19:27:25 +00:00
13 changed files with 310 additions and 81 deletions
-2
View File
@@ -2,8 +2,6 @@ images:
- name: cloudflared
dockerfile: Dockerfile
context: .
versions:
- latest
registries:
- name: docker.io/cloudflare
user: env:DOCKER_USER
+27 -10
View File
@@ -4,7 +4,8 @@ VERSION_FLAGS := -ldflags='-X "main.Version=$(VERSION)" -X "main.BuildTime=$(DAT
IMPORT_PATH := github.com/cloudflare/cloudflared
PACKAGE_DIR := $(CURDIR)/packaging
INSTALL_BINDIR := usr/local/bin
INSTALL_BINDIR := /usr/bin/
MAN_DIR := /usr/share/man/man1/
EQUINOX_FLAGS = --version="$(VERSION)" \
--platforms="$(EQUINOX_BUILD_PLATFORMS)" \
@@ -48,6 +49,14 @@ else
EXECUTABLE_PATH=./cloudflared
endif
ifeq ($(FLAVOR), centos-7)
TARGET_PUBLIC_REPO ?= el7
else ifeq ($(FLAVOR), centos-6)
TARGET_PUBLIC_REPO ?= el6
else
TARGET_PUBLIC_REPO ?= $(FLAVOR)
endif
.PHONY: all
all: cloudflared test
@@ -74,7 +83,7 @@ test-ssh-server:
define publish_package
for HOST in $(CF_PKG_HOSTS); do \
ssh-keyscan -t rsa $$HOST >> ~/.ssh/known_hosts; \
scp -4 cloudflared_$(VERSION)_amd64.deb cfsync@$$HOST:/state/cf-pkg/staging/$(1)/$(FLAVOR)/cloudflared/; \
scp -4 cloudflared_$(VERSION)_amd64.deb cfsync@$$HOST:/state/cf-pkg/staging/$(1)/$(TARGET_PUBLIC_REPO)/cloudflared/; \
done
endef
@@ -86,19 +95,27 @@ publish-deb: cloudflared-deb
publish-rpm: cloudflared-rpm
$(call publish_package,yum)
.PHONY: cloudflared-deb
cloudflared-deb: cloudflared
define build_package
mkdir -p $(PACKAGE_DIR)
cp cloudflared $(PACKAGE_DIR)/cloudflared
fakeroot fpm -C $(PACKAGE_DIR) -s dir -t deb --deb-compression bzip2 \
-a $(TARGET_ARCH) -v $(VERSION) -n cloudflared cloudflared=/usr/local/bin/
cat cloudflared_man_template | sed -e 's/\$${VERSION}/$(VERSION)/; s/\$${DATE}/$(DATE)/' > $(PACKAGE_DIR)/cloudflared.1
fakeroot fpm -C $(PACKAGE_DIR) -s dir -t $(1) --$(1)-compression bzip2 \
--description 'Cloudflare Argo tunnel daemon' \
--vendor 'Cloudflare' \
--license 'Cloudflare Service Agreement' \
--url 'https://github.com/cloudflare/cloudflared' \
-m 'Cloudflare <support@cloudflare.com>' \
-a $(TARGET_ARCH) -v $(VERSION) -n cloudflared --after-install postinst.sh --after-remove postrm.sh \
cloudflared=$(INSTALL_BINDIR) cloudflared.1=$(MAN_DIR)
endef
.PHONY: cloudflared-deb
cloudflared-deb: cloudflared
$(call build_package,deb)
.PHONY: cloudflared-rpm
cloudflared-rpm: cloudflared
mkdir -p $(PACKAGE_DIR)
cp cloudflared $(PACKAGE_DIR)/cloudflared
fakeroot fpm -C $(PACKAGE_DIR) -s dir -t rpm --rpm-compression bzip2 \
-a $(TARGET_ARCH) -v $(VERSION) -n cloudflared cloudflared=/usr/local/bin/
$(call build_package,rpm)
.PHONY: cloudflared-darwin-amd64.tgz
cloudflared-darwin-amd64.tgz: cloudflared
+11
View File
@@ -1,3 +1,14 @@
2020.7.2
- 2020-07-02 AUTH-2644: Change install location and add man page
- 2020-07-02 TUN-3131: Allow user to specify tunnel credentials path, and remove it in tunnel delete command
- 2020-07-03 TUN-3008: Implement cloudflared tunnel cleanup command
- 2020-07-02 TUN-3150: cloudflared tunnel list's table should use intelligent column width
- 2020-07-07 TUN-3169: Move on to the next address when edge returns duplicate connection. There's no point in trying to connect to the same address since it will be hashed to the same metal. Improve logging of errors from serve tunnel loop, hide useless context cancelled error.
- 2020-07-08 beautify package meta information generated by fpm (#218)
- 2020-07-06 AUTH-2871: fix rpm builds
- 2020-07-08 AUTH-2858: Set file to disable autoupdate
- 2020-07-09 AUTH-2872: Adds centos-6 build
2020.7.1
- 2020-07-02 DEVTOOLS-7321: Push GitHub homebrew updates to master
- 2020-07-06 TUN-3161: Upgrade golang.org/x/ deps
+42 -1
View File
@@ -170,10 +170,40 @@ jessie: *stretch
buster: *stretch
centos-6:
build-rpm:
build_dir: *build_dir
builddeps: &el6_builddeps
- https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
post-cache:
- source /usr/local/rvm/scripts/rvm
- rvm use 1.9
- sudo yum install -y fakeroot
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
- export PATH=$PATH:/usr/local/go/bin
- export GOOS=linux
- export GOARCH=amd64
- make cloudflared-rpm
publish-rpm:
build_dir: *build_dir
builddeps: *el6_builddeps
post-cache:
- source /usr/local/rvm/scripts/rvm
- rvm use 1.9
- sudo yum install -y fakeroot
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
- export PATH=$PATH:/usr/local/go/bin
- export GOOS=linux
- export GOARCH=amd64
- make publish-rpm
centos-7:
publish-rpm:
build_dir: *build_dir
builddeps:
builddeps: &el7_builddeps
- https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
post-cache:
- sudo yum install -y fakeroot
@@ -183,6 +213,17 @@ centos-7:
- export GOOS=linux
- export GOARCH=amd64
- make publish-rpm
build-rpm:
build_dir: *build_dir
builddeps: *el7_builddeps
post-cache:
- sudo yum install -y fakeroot
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
- export PATH=$PATH:/usr/local/go/bin
- export GOOS=linux
- export GOARCH=amd64
- make cloudflared-rpm
# cfsetup compose
default-stack: test_dbconnect
+6
View File
@@ -0,0 +1,6 @@
.\" Manpage for cloudflared.
.TH man 1 ${DATE} "${VERSION}" "cloudflared man page"
.SH NAME
cloudflared \- creates a connection to the cloudflare edge network
.SH DESCRIPTION
cloudflared creates a persistent connection between a local service and the Cloudflare network. Once the daemon is running and the Tunnel has been configured, the local service can be locked down to only allow connections from Cloudflare.
+1
View File
@@ -173,6 +173,7 @@ func Commands() []*cli.Command {
subcommands = append(subcommands, buildListCommand())
subcommands = append(subcommands, buildDeleteCommand())
subcommands = append(subcommands, buildRunCommand())
subcommands = append(subcommands, buildCleanupCommand())
cmds = append(cmds, &cli.Command{
Name: "tunnel",
+144 -38
View File
@@ -9,21 +9,28 @@ import (
"path/filepath"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/google/uuid"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"gopkg.in/urfave/cli.v2"
"gopkg.in/yaml.v2"
"github.com/cloudflare/cloudflared/certutil"
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
"github.com/cloudflare/cloudflared/origin"
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
"github.com/cloudflare/cloudflared/tunnelstore"
)
const (
credFileFlagAlias = "cred-file"
)
var (
showDeletedFlag = &cli.BoolFlag{
Name: "show-deleted",
@@ -43,6 +50,11 @@ var (
"overwrite the previous tunnel. If you want to use a single hostname with multiple " +
"tunnels, you can do so with Cloudflare's Load Balancer product.",
}
credentialsFileFlag = &cli.StringFlag{
Name: "credentials-file",
Aliases: []string{credFileFlagAlias},
Usage: "File path of tunnel credentials",
}
)
const hideSubcommands = true
@@ -81,11 +93,7 @@ func createTunnel(c *cli.Context) error {
return err
}
originCertPath, err := findOriginCert(c, logger)
if err != nil {
return errors.Wrap(err, "Error locating origin cert")
}
cert, err := getOriginCertFromContext(originCertPath, logger)
cert, originCertPath, err := getOriginCertFromContext(c, logger)
if err != nil {
return err
}
@@ -118,13 +126,15 @@ func createTunnel(c *cli.Context) error {
return nil
}
func tunnelFilePath(tunnelID, originCertPath string) (string, error) {
func tunnelFilePath(tunnelID, directory string) (string, error) {
fileName := fmt.Sprintf("%v.json", tunnelID)
return filepath.Clean(fmt.Sprintf("%v/../%v", originCertPath, fileName)), nil
filePath := filepath.Clean(fmt.Sprintf("%s/%s", directory, fileName))
return homedir.Expand(filePath)
}
func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSecret []byte, logger logger.Service) error {
filePath, err := tunnelFilePath(tunnelID, originCertPath)
originCertDir := filepath.Dir(originCertPath)
filePath, err := tunnelFilePath(tunnelID, originCertDir)
if err != nil {
return err
}
@@ -140,8 +150,8 @@ func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSe
return ioutil.WriteFile(filePath, body, 400)
}
func readTunnelCredentials(tunnelID, originCertPath string) (*pogs.TunnelAuth, error) {
filePath, err := tunnelFilePath(tunnelID, originCertPath)
func readTunnelCredentials(c *cli.Context, tunnelID string, logger logger.Service) (*pogs.TunnelAuth, error) {
filePath, err := tunnelCredentialsPath(c, tunnelID, logger)
if err != nil {
return nil, err
}
@@ -157,6 +167,42 @@ func readTunnelCredentials(tunnelID, originCertPath string) (*pogs.TunnelAuth, e
return &auth, nil
}
func tunnelCredentialsPath(c *cli.Context, tunnelID string, logger logger.Service) (string, error) {
if filePath := c.String("credentials-file"); filePath != "" {
if validFilePath(filePath) {
return filePath, nil
}
}
// Fallback to look for tunnel credentials in the origin cert directory
if originCertPath, err := findOriginCert(c, logger); err == nil {
originCertDir := filepath.Dir(originCertPath)
if filePath, err := tunnelFilePath(tunnelID, originCertDir); err == nil {
if validFilePath(filePath) {
return filePath, nil
}
}
}
// Last resort look under default config directories
for _, configDir := range config.DefaultConfigDirs {
if filePath, err := tunnelFilePath(tunnelID, configDir); err == nil {
if validFilePath(filePath) {
return filePath, nil
}
}
}
return "", fmt.Errorf("Tunnel credentials file not found")
}
func validFilePath(path string) bool {
fileStat, err := os.Stat(path)
if err != nil {
return false
}
return !fileStat.IsDir()
}
func buildListCommand() *cli.Command {
return &cli.Command{
Name: "list",
@@ -174,11 +220,7 @@ func listTunnels(c *cli.Context) error {
return errors.Wrap(err, "error setting up logger")
}
originCertPath, err := findOriginCert(c, logger)
if err != nil {
return errors.Wrap(err, "Error locating origin cert")
}
cert, err := getOriginCertFromContext(originCertPath, logger)
cert, _, err := getOriginCertFromContext(c, logger)
if err != nil {
return err
}
@@ -203,12 +245,9 @@ func listTunnels(c *cli.Context) error {
if outputFormat := c.String(outputFormatFlag.Name); outputFormat != "" {
return renderOutput(outputFormat, tunnels)
}
if len(tunnels) > 0 {
const listFormat = "%-40s%-30s%-30s%s\n"
fmt.Printf(listFormat, "ID", "NAME", "CREATED", "CONNECTIONS")
for _, t := range tunnels {
fmt.Printf(listFormat, t.ID, t.Name, t.CreatedAt.Format(time.RFC3339), fmtConnections(t.Connections))
}
fmtAndPrintTunnelList(tunnels)
} else {
fmt.Println("You have no tunnels, use 'cloudflared tunnel create' to define a new tunnel")
}
@@ -216,6 +255,30 @@ func listTunnels(c *cli.Context) error {
return nil
}
func fmtAndPrintTunnelList(tunnels []tunnelstore.Tunnel) {
const (
minWidth = 0
tabWidth = 8
padding = 1
padChar = ' '
flags = 0
)
writer := tabwriter.NewWriter(os.Stdout, minWidth, tabWidth, padding, padChar, flags)
// Print column headers with tabbed columns
fmt.Fprintln(writer, "ID\tNAME\tCREATED\tCONNECTIONS\t")
// Loop through tunnels, create formatted string for each, and print using tabwriter
for _, t := range tunnels {
formattedStr := fmt.Sprintf("%s\t%s\t%s\t%s\t", t.ID, t.Name, t.CreatedAt.Format(time.RFC3339), fmtConnections(t.Connections))
fmt.Fprintln(writer, formattedStr)
}
// Write data buffered in tabwriter to output
writer.Flush()
}
func fmtConnections(connections []tunnelstore.Connection) string {
// Count connections per colo
@@ -246,6 +309,7 @@ func buildDeleteCommand() *cli.Command {
Usage: "Delete existing tunnel with given ID",
ArgsUsage: "TUNNEL-ID",
Hidden: hideSubcommands,
Flags: []cli.Flag{credentialsFileFlag},
}
}
@@ -260,11 +324,7 @@ func deleteTunnel(c *cli.Context) error {
return errors.Wrap(err, "error setting up logger")
}
originCertPath, err := findOriginCert(c, logger)
if err != nil {
return errors.Wrap(err, "Error locating origin cert")
}
cert, err := getOriginCertFromContext(originCertPath, logger)
cert, _, err := getOriginCertFromContext(c, logger)
if err != nil {
return err
}
@@ -274,6 +334,16 @@ func deleteTunnel(c *cli.Context) error {
return errors.Wrapf(err, "Error deleting tunnel %s", id)
}
tunnelCredentialsPath, err := tunnelCredentialsPath(c, id, logger)
if err != nil {
logger.Infof("Cannot locate tunnel credentials to delete, error: %v. Please delete the file manually", err)
return nil
}
if err = os.Remove(tunnelCredentialsPath); err != nil {
logger.Infof("Cannot delete tunnel credentials, error: %v. Please delete the file manually", err)
}
return nil
}
@@ -295,22 +365,25 @@ func newTunnelstoreClient(c *cli.Context, cert *certutil.OriginCert, logger logg
return client
}
func getOriginCertFromContext(originCertPath string, logger logger.Service) (*certutil.OriginCert, error) {
func getOriginCertFromContext(c *cli.Context, logger logger.Service) (cert *certutil.OriginCert, originCertPath string, err error) {
originCertPath, err = findOriginCert(c, logger)
if err != nil {
return nil, "", errors.Wrap(err, "Error locating origin cert")
}
blocks, err := readOriginCert(originCertPath, logger)
if err != nil {
return nil, errors.Wrapf(err, "Can't read origin cert from %s", originCertPath)
return nil, "", errors.Wrapf(err, "Can't read origin cert from %s", originCertPath)
}
cert, err := certutil.DecodeOriginCert(blocks)
cert, err = certutil.DecodeOriginCert(blocks)
if err != nil {
return nil, errors.Wrap(err, "Error decoding origin cert")
return nil, "", errors.Wrap(err, "Error decoding origin cert")
}
if cert.AccountID == "" {
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)
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)
}
return cert, nil
return cert, originCertPath, nil
}
func buildRunCommand() *cli.Command {
@@ -320,7 +393,7 @@ func buildRunCommand() *cli.Command {
Usage: "Proxy a local web server by running the given tunnel",
ArgsUsage: "TUNNEL-ID",
Hidden: hideSubcommands,
Flags: []cli.Flag{forceFlag},
Flags: []cli.Flag{forceFlag, credentialsFileFlag},
}
}
@@ -339,14 +412,47 @@ func runTunnel(c *cli.Context) error {
return errors.Wrap(err, "error setting up logger")
}
originCertPath, err := findOriginCert(c, logger)
if err != nil {
return errors.Wrap(err, "Error locating origin cert")
}
credentials, err := readTunnelCredentials(id, originCertPath)
credentials, err := readTunnelCredentials(c, id, logger)
if err != nil {
return err
}
logger.Debugf("Read credentials for %v", credentials.AccountTag)
return StartServer(c, version, shutdownC, graceShutdownC, &origin.NamedTunnelConfig{Auth: *credentials, ID: tunnelID})
}
func buildCleanupCommand() *cli.Command {
return &cli.Command{
Name: "cleanup",
Action: cliutil.ErrorHandler(cleanupConnections),
Usage: "Cleanup connections for the tunnel with given IDs",
ArgsUsage: "TUNNEL-IDS",
Hidden: hideSubcommands,
}
}
func cleanupConnections(c *cli.Context) error {
if c.NArg() < 1 {
return cliutil.UsageError(`"cloudflared tunnel cleanup" requires at least 1 argument, the IDs of the tunnels to cleanup connections.`)
}
logger, err := logger.New()
if err != nil {
return errors.Wrap(err, "error setting up logger")
}
cert, _, err := getOriginCertFromContext(c, logger)
if err != nil {
return err
}
client := newTunnelstoreClient(c, cert, logger)
for i := 0; i < c.NArg(); i++ {
id := c.Args().Get(i)
logger.Infof("Cleanup connection for tunnel %s", id)
if err := client.CleanupConnections(id); err != nil {
logger.Errorf("Error cleaning up connections for tunnel %s, error :%v", id, err)
}
}
return nil
}
+8 -2
View File
@@ -1,9 +1,12 @@
package tunnel
import (
"fmt"
"path/filepath"
"testing"
"github.com/cloudflare/cloudflared/tunnelstore"
"github.com/mitchellh/go-homedir"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
@@ -72,8 +75,11 @@ func Test_fmtConnections(t *testing.T) {
}
func TestTunnelfilePath(t *testing.T) {
actual, err := tunnelFilePath("tunnel", "~/.cloudflared/cert.pem")
originCertDir := filepath.Dir("~/.cloudflared/cert.pem")
actual, err := tunnelFilePath("tunnel", originCertDir)
assert.NoError(t, err)
expected := "~/.cloudflared/tunnel.json"
homeDir, err := homedir.Dir()
assert.NoError(t, err)
expected := fmt.Sprintf("%s/.cloudflared/tunnel.json", homeDir)
assert.Equal(t, expected, actual)
}
+23 -4
View File
@@ -4,12 +4,14 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"time"
"golang.org/x/crypto/ssh/terminal"
"gopkg.in/urfave/cli.v2"
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
"github.com/cloudflare/cloudflared/logger"
"github.com/equinox-io/equinox"
"github.com/facebookgo/grace/gracenet"
@@ -17,10 +19,12 @@ import (
)
const (
DefaultCheckUpdateFreq = time.Hour * 24
appID = "app_idCzgxYerVD"
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/"
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
DefaultCheckUpdateFreq = time.Hour * 24
appID = "app_idCzgxYerVD"
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/"
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
noUpdateManagedPackageMessage = "cloudflared will not automatically update if installed by a package manager."
isManagedInstallFile = ".installedFromPackageManager"
)
var (
@@ -98,6 +102,11 @@ func Update(_ *cli.Context) error {
return errors.Wrap(err, "error setting up logger")
}
if wasInstalledFromPackageManager() {
logger.Error("cloudflared was installed by a package manager. Please update using the same method.")
return nil
}
updateOutcome := loggedUpdate(logger)
if updateOutcome.Error != nil {
return &statusErr{updateOutcome.Error}
@@ -217,6 +226,11 @@ func SupportAutoUpdate(logger logger.Service) bool {
return false
}
if wasInstalledFromPackageManager() {
logger.Info(noUpdateManagedPackageMessage)
return false
}
if isRunningFromTerminal() {
logger.Info(noUpdateInShellMessage)
return false
@@ -224,6 +238,11 @@ func SupportAutoUpdate(logger logger.Service) bool {
return true
}
func wasInstalledFromPackageManager() bool {
ok, _ := config.FileExists(filepath.Join(config.DefaultUnixConfigLocation, isManagedInstallFile))
return ok
}
func isRunningFromTerminal() bool {
return terminal.IsTerminal(int(os.Stdout.Fd()))
}
+17 -13
View File
@@ -105,7 +105,7 @@ type dupConnRegisterTunnelError struct{}
var errDuplicationConnection = &dupConnRegisterTunnelError{}
func (e dupConnRegisterTunnelError) Error() string {
return "already connected to this server"
return "already connected to this server, trying another address"
}
type muxerShutdownError struct{}
@@ -376,29 +376,33 @@ func ServeTunnel(
err = errGroup.Wait()
if err != nil {
switch castedErr := err.(type) {
case dupConnRegisterTunnelError:
logger.Info("Already connected to this server, selecting a different one")
return err, true
case serverRegisterTunnelError:
logger.Errorf("Register tunnel error from server side: %s", castedErr.cause)
switch err := err.(type) {
case *dupConnRegisterTunnelError:
// don't retry this connection anymore, let supervisor pick new a address
return err, false
case *serverRegisterTunnelError:
logger.Errorf("Register tunnel error from server side: %s", err.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 {
logger.Error(activeIncidentsMsg(incidents))
}
return castedErr.cause, !castedErr.permanent
case clientRegisterTunnelError:
logger.Errorf("Register tunnel error on client side: %s", castedErr.cause)
return err.cause, !err.permanent
case *clientRegisterTunnelError:
logger.Errorf("Register tunnel error on client side: %s", err.cause)
return err, true
case muxerShutdownError:
case *muxerShutdownError:
logger.Info("Muxer shutdown")
return err, true
case *ReconnectSignal:
logger.Infof("Restarting connection %d due to reconnect signal in %d seconds", connectionIndex, castedErr.Delay)
castedErr.DelayBeforeReconnect()
logger.Infof("Restarting connection %d due to reconnect signal in %d seconds", connectionIndex, err.Delay)
err.DelayBeforeReconnect()
return err, true
default:
if err == context.Canceled {
logger.Debugf("Serve tunnel error: %s", err)
return err, false
}
logger.Errorf("Serve tunnel error: %s", err)
return err, true
}
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
set -eu
ln -s /usr/bin/cloudflared /usr/local/bin/cloudflared
mkdir -p /usr/local/etc/cloudflared/
touch /usr/local/etc/cloudflared/.installedFromPackageManager || true
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
set -eu
rm /usr/local/bin/cloudflared
rm /usr/local/etc/cloudflared/.installedFromPackageManager || true
+22 -11
View File
@@ -41,9 +41,10 @@ type Connection struct {
type Client interface {
CreateTunnel(name string, tunnelSecret []byte) (*Tunnel, error)
GetTunnel(id string) (*Tunnel, error)
DeleteTunnel(id string) error
GetTunnel(tunnelID string) (*Tunnel, error)
DeleteTunnel(tunnelID string) error
ListTunnels() ([]Tunnel, error)
CleanupConnections(tunnelID string) error
}
type RESTClient struct {
@@ -104,11 +105,11 @@ func (r *RESTClient) CreateTunnel(name string, tunnelSecret []byte) (*Tunnel, er
return nil, ErrTunnelNameConflict
}
return nil, statusCodeToError("create", resp)
return nil, statusCodeToError("create tunnel", resp)
}
func (r *RESTClient) GetTunnel(id string) (*Tunnel, error) {
resp, err := r.sendRequest("GET", id, nil)
func (r *RESTClient) GetTunnel(tunnelID string) (*Tunnel, error) {
resp, err := r.sendRequest("GET", tunnelID, nil)
if err != nil {
return nil, errors.Wrap(err, "REST request failed")
}
@@ -118,17 +119,17 @@ func (r *RESTClient) GetTunnel(id string) (*Tunnel, error) {
return unmarshalTunnel(resp.Body)
}
return nil, statusCodeToError("read", resp)
return nil, statusCodeToError("get tunnel", resp)
}
func (r *RESTClient) DeleteTunnel(id string) error {
resp, err := r.sendRequest("DELETE", id, nil)
func (r *RESTClient) DeleteTunnel(tunnelID string) error {
resp, err := r.sendRequest("DELETE", tunnelID, nil)
if err != nil {
return errors.Wrap(err, "REST request failed")
}
defer resp.Body.Close()
return statusCodeToError("delete", resp)
return statusCodeToError("delete tunnel", resp)
}
func (r *RESTClient) ListTunnels() ([]Tunnel, error) {
@@ -146,7 +147,17 @@ func (r *RESTClient) ListTunnels() ([]Tunnel, error) {
return tunnels, nil
}
return nil, statusCodeToError("list", resp)
return nil, statusCodeToError("list tunnels", resp)
}
func (r *RESTClient) CleanupConnections(tunnelID string) error {
resp, err := r.sendRequest("DELETE", fmt.Sprintf("%s/connections", tunnelID), nil)
if err != nil {
return errors.Wrap(err, "REST request failed")
}
defer resp.Body.Close()
return statusCodeToError("cleanup connections", resp)
}
func (r *RESTClient) resolve(target string) string {
@@ -189,6 +200,6 @@ func statusCodeToError(op string, resp *http.Response) error {
case http.StatusNotFound:
return ErrNotFound
}
return errors.Errorf("API call to %s tunnel failed with status %d: %s", op,
return errors.Errorf("API call to %s failed with status %d: %s", op,
resp.StatusCode, http.StatusText(resp.StatusCode))
}