Skip to content

Commit

Permalink
Add build flag to link the go-fuseftp implementation.
Browse files Browse the repository at this point in the history
This build-flag is not enabled by default, but can be used when there
is a desire to build a telepresence client that links the fuseftp
implementation instead of using a remote process via gRPC.

Signed-off-by: Thomas Hallgren <[email protected]>
  • Loading branch information
thallgren committed Feb 3, 2025
1 parent 6f9da09 commit 870c9f4
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 28 deletions.
3 changes: 3 additions & 0 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ following Free and Open Source software:
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb MIT license
github.com/huandu/xstrings v1.5.0 MIT license
github.com/inconshreveable/mousetrap v1.1.0 Apache License 2.0
github.com/jlaffaye/ftp v0.2.0 ISC license
github.com/jmoiron/sqlx v1.4.0 MIT license
github.com/josharian/intern v1.0.1-0.20211109044230-42b52b674af5 MIT license
github.com/json-iterator/go v1.1.12 MIT license
Expand Down Expand Up @@ -128,10 +129,12 @@ following Free and Open Source software:
github.com/spf13/cobra v1.8.1 Apache License 2.0
github.com/spf13/pflag v1.0.6 3-clause BSD license
github.com/stretchr/testify v1.10.0 MIT license
github.com/telepresenceio/go-fuseftp v0.6.1 Apache License 2.0
github.com/telepresenceio/go-fuseftp/rpc v0.6.1 Apache License 2.0
github.com/telepresenceio/telepresence/rpc/v2 (modified) Apache License 2.0
github.com/vishvananda/netlink v1.3.0 Apache License 2.0
github.com/vishvananda/netns v0.0.5 Apache License 2.0
github.com/winfsp/cgofuse v1.6.0 MIT license
github.com/x448/float16 v0.8.4 MIT license
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb Apache License 2.0
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 Apache License 2.0
Expand Down
42 changes: 24 additions & 18 deletions build-aux/main.mk
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,23 @@ export DOCKER_BUILDKIT := 1
.PHONY: FORCE
FORCE:

EXTERNAL_FUSEFTP=0
LINKED_FUSEFTP=0

# Build with CGO_ENABLED=0 on all platforms to ensure that the binary is as
# portable as possible, but we must make an exception for darwin, because
# the Go implementation of the DNS resolver doesn't work properly there unless
# it's using clib
ifeq ($(GOOS),darwin)
CGO_ENABLED=1
else
ifeq ($(GOOS),linux)
# The winfsp module requires CGO on Linux.
CGO_ENABLED=$(LINKED_FUSEFTP)
else
CGO_ENABLED=0
endif
endif

ifeq ($(GOOS),windows)
BEXE=.exe
Expand All @@ -52,8 +60,6 @@ BEXE=
BZIP=
endif

EMBED_FUSEFTP=1

# Generate: artifacts that get checked in to Git
# ==============================================

Expand Down Expand Up @@ -161,10 +167,19 @@ else
sdkroot=
endif

BUILD_TAGS=
build-deps:

ifeq ($(DOCKER_BUILD),1)
BUILD_TAGS=-tags docker
else
ifeq ($(EXTERNAL_FUSEFTP),1)
BUILD_TAGS=-tags external_fuseftp
build-deps:
else
ifeq ($(EMBED_FUSEFTP),1)
ifeq ($(LINKED_FUSEFTP),1)
BUILD_TAGS=-tags linked_fuseftp
else
FUSEFTP_VERSION=$(shell go list -m -f {{.Version}} github.com/telepresenceio/go-fuseftp/rpc)

$(BUILDDIR)/fuseftp-$(GOOS)-$(GOARCH)$(BEXE): go.mod
Expand All @@ -175,8 +190,7 @@ pkg/client/remotefs/fuseftp.bits: $(BUILDDIR)/fuseftp-$(GOOS)-$(GOARCH)$(BEXE) F
cp $< $@

build-deps: pkg/client/remotefs/fuseftp.bits
else
build-deps:
endif
endif
endif

Expand Down Expand Up @@ -208,14 +222,10 @@ $(TELEPRESENCE): build-deps $(BINDIR)/wintun.dll FORCE
endif
mkdir -p $(@D)
ifeq ($(DOCKER_BUILD),1)
CGO_ENABLED=$(CGO_ENABLED) $(sdkroot) go build -tags docker -trimpath -ldflags=-X=$(PKG_VERSION).Version=$(TELEPRESENCE_VERSION) -o $@ ./cmd/telepresence
CGO_ENABLED=$(CGO_ENABLED) $(sdkroot) go build $(BUILD_TAGS) -trimpath -ldflags=-X=$(PKG_VERSION).Version=$(TELEPRESENCE_VERSION) -o $@ ./cmd/telepresence
else
# -buildmode=pie addresses https://github.com/datawire/telepresence2-proprietary/issues/315
ifeq ($(EMBED_FUSEFTP),1)
CGO_ENABLED=$(CGO_ENABLED) $(sdkroot) go build -tags embed_fuseftp -buildmode=pie -trimpath -ldflags=-X=$(PKG_VERSION).Version=$(TELEPRESENCE_VERSION) -o $@ ./cmd/telepresence
else
CGO_ENABLED=$(CGO_ENABLED) $(sdkroot) go build -buildmode=pie -trimpath -ldflags=-X=$(PKG_VERSION).Version=$(TELEPRESENCE_VERSION) -o $@ ./cmd/telepresence
endif
CGO_ENABLED=$(CGO_ENABLED) $(sdkroot) go build $(BUILD_TAGS) -buildmode=pie -trimpath -ldflags=-X=$(PKG_VERSION).Version=$(TELEPRESENCE_VERSION) -o $@ ./cmd/telepresence
endif

ifeq ($(GOOS),windows)
Expand Down Expand Up @@ -375,7 +385,7 @@ shellscripts += ./packaging/windows-package.sh

lint: lint-rpc lint-go

GOLANGCI_VERSION:=v1.62.2
GOLANGCI_VERSION:=v1.63.4

lint-go: lint-deps ## (QA) Run the golangci-lint
$(eval badimports = $(shell find cmd integration_test pkg -name '*.go' | grep -v '/mocks/' | xargs $(tools/gosimports) --local github.com/datawire/,github.com/telepresenceio/ -l))
Expand All @@ -402,7 +412,7 @@ ifeq ($(GOHOSTOS),windows)
run --timeout 8m --fix ./cmd/telepresence/... ./integration_test/... ./pkg/...
else
docker run -e GOOS=$(GOOS) --rm -v $$(pwd):/app -v ~/.cache/golangci-lint/$(GOLANGCI_VERSION):/root/.cache -w /app golangci/golangci-lint:$(GOLANGCI_VERSION) golangci-lint \
run --timeout 8m --fix ./...
run --timeout 8m --fix ./cmd/telepresence/... ./cmd/manager/cmd/... ./cmd/agent/cmd/... ./integration_test/... ./pkg/...
endif
$(tools/protolint) lint --fix rpc || true

Expand Down Expand Up @@ -431,11 +441,7 @@ endif
# is only used for extensions. Therefore, we want to validate that our tests, and
# telepresence, run without requiring any outside dependencies.
set -o pipefail
ifeq ($(EMBED_FUSEFTP),1)
TELEPRESENCE_MAX_LOGFILES=300 TELEPRESENCE_LOGIN_DOMAIN=127.0.0.1 CGO_ENABLED=$(CGO_ENABLED) go test -tags embed_fuseftp -failfast -json -timeout=80m ./integration_test/... | $(tools/test-report)
else
TELEPRESENCE_MAX_LOGFILES=300 TELEPRESENCE_LOGIN_DOMAIN=127.0.0.1 CGO_ENABLED=$(CGO_ENABLED) go test -failfast -json -timeout=80m ./integration_test/... | $(tools/test-report)
endif
TELEPRESENCE_MAX_LOGFILES=300 TELEPRESENCE_LOGIN_DOMAIN=127.0.0.1 CGO_ENABLED=$(CGO_ENABLED) go test $(BUILD_TAGS) -failfast -json -timeout=80m ./integration_test/... | $(tools/test-report)

.PHONY: _login
_login:
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
github.com/telepresenceio/go-fuseftp v0.6.1
github.com/telepresenceio/go-fuseftp/rpc v0.6.1
github.com/telepresenceio/telepresence/rpc/v2 v2.21.1
github.com/vishvananda/netlink v1.3.0
Expand Down Expand Up @@ -115,6 +116,7 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jlaffaye/ftp v0.2.0 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/josharian/intern v1.0.1-0.20211109044230-42b52b674af5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
Expand Down Expand Up @@ -154,6 +156,7 @@ require (
github.com/shopspring/decimal v1.4.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
github.com/winfsp/cgofuse v1.6.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/josharian/intern v1.0.1-0.20211109044230-42b52b674af5 h1:f8m7k2T128wwQej7ewBVgUfHNgCu3uXod6wopWGDvE4=
Expand Down Expand Up @@ -397,13 +399,17 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/telepresenceio/go-fuseftp v0.6.1 h1:v3Hqwl2rDxep3kHfEOwsXijOOCXT3blRGN0cs45uR9A=
github.com/telepresenceio/go-fuseftp v0.6.1/go.mod h1:EXH+oL5GalxZ/pZV5MCHFYW3aLW1SRxV5wSedWoSS2g=
github.com/telepresenceio/go-fuseftp/rpc v0.6.1 h1:y/RA6OiE6qM47SiBeSaez+a+PVdIUEl68M7Wl+SqJcc=
github.com/telepresenceio/go-fuseftp/rpc v0.6.1/go.mod h1:jLvPHOWARcSRV5b1zxRYbv4Sa5VlMZxpnyTpCKrlPzA=
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/winfsp/cgofuse v1.6.0 h1:re3W+HTd0hj4fISPBqfsrwyvPFpzqhDu8doJ9nOPDB0=
github.com/winfsp/cgofuse v1.6.0/go.mod h1:uxjoF2jEYT3+x+vC2KJddEGdk/LU8pRowXmyVMHSV5I=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/remotefs/fuseftp.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !docker
//go:build !docker && !linked_fuseftp

package remotefs

Expand Down
15 changes: 10 additions & 5 deletions pkg/client/remotefs/fuseftp_docker.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
//go:build docker
// +build docker

package remotefs

import (
"context"
"errors"
"sync"

"github.com/telepresenceio/go-fuseftp/rpc"
)

// NewFTPMounter returns nil. It's here to satisfy the linker.
func NewFTPMounter(rpc.FuseFTPClient, *sync.WaitGroup) Mounter {
return nil
}

type fuseFtpMgr struct{}

type FuseFTPManager interface {
DeferInit(ctx context.Context) error
GetFuseFTPClient(ctx context.Context) rpc.FuseFTPClient
DeferInit(context.Context) error
GetFuseFTPClient(context.Context) rpc.FuseFTPClient
}

func NewFuseFTPManager() FuseFTPManager {
return &fuseFtpMgr{}
}

func (s *fuseFtpMgr) DeferInit(ctx context.Context) error {
func (s *fuseFtpMgr) DeferInit(context.Context) error {
return errors.New("fuseftp client is not available")
}

func (s *fuseFtpMgr) GetFuseFTPClient(ctx context.Context) rpc.FuseFTPClient {
func (s *fuseFtpMgr) GetFuseFTPClient(context.Context) rpc.FuseFTPClient {
return nil
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build embed_fuseftp && !docker
//go:build !(docker || external_fuseftp || linked_fuseftp)

package remotefs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !embed_fuseftp && !docker
//go:build external_fuseftp && !docker

package remotefs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !(linked_fuseftp || docker)

package remotefs

import (
Expand Down
87 changes: 87 additions & 0 deletions pkg/client/remotefs/fuseftp_linked.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//go:build linked_fuseftp && !docker

package remotefs

import (
"context"
"net/netip"
"strings"
"sync"
"time"

"github.com/sirupsen/logrus"

"github.com/datawire/dlib/dlog"
"github.com/telepresenceio/go-fuseftp/pkg/fs"
"github.com/telepresenceio/go-fuseftp/rpc"
"github.com/telepresenceio/telepresence/v2/pkg/agentconfig"
"github.com/telepresenceio/telepresence/v2/pkg/client"
)

type ftpMounter struct {
mountPoint string
cancel context.CancelFunc
ftpClient fs.FTPClient
iceptWG *sync.WaitGroup
}

type fuseFtpMgr struct{}

type FuseFTPManager interface {
DeferInit(ctx context.Context) error
GetFuseFTPClient(ctx context.Context) rpc.FuseFTPClient
}

func NewFuseFTPManager() FuseFTPManager {
return &fuseFtpMgr{}
}

func (s *fuseFtpMgr) DeferInit(_ context.Context) error {
return nil
}

func (s *fuseFtpMgr) GetFuseFTPClient(_ context.Context) rpc.FuseFTPClient {
return rpc.NewFuseFTPClient(nil)
}

func NewFTPMounter(_ rpc.FuseFTPClient, iceptWG *sync.WaitGroup) Mounter {
// The FTPClient uses the global logrus logger. It's very verbose on DebugLevel.
logrus.SetLevel(logrus.InfoLevel)
return &ftpMounter{iceptWG: iceptWG}
}

func (m *ftpMounter) Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podAddrPort netip.AddrPort, ro bool) error {
roTxt := ""
if ro {
roTxt = " read-only"
}
if m.ftpClient == nil {
cfg := client.GetConfig(ctx)
dlog.Infof(ctx, "Mounting FTP file system for container %s[%s] (address %s)%s at %q", workload, container, podAddrPort, roTxt, clientMountPoint)
// FTPs remote mount is already relative to the agentconfig.ExportsMountPoint
rmp := strings.TrimPrefix(mountPoint, agentconfig.ExportsMountPoint)
ftpClient, err := fs.NewFTPClient(ctx, podAddrPort, rmp, ro, cfg.Timeouts().Get(client.TimeoutFtpReadWrite))
if err != nil {
return err
}
host := fs.NewHost(ftpClient, clientMountPoint)
if err = host.Start(ctx, 5*time.Second); err != nil {
return err
}

m.ftpClient = ftpClient
// Ensure unmount when intercept context is cancelled
m.iceptWG.Add(1)
go func() {
defer m.iceptWG.Done()
<-ctx.Done()
dlog.Debugf(ctx, "Unmounting FTP file system for container %s[%s] (address %s) at %q", workload, container, podAddrPort, clientMountPoint)
}()
dlog.Infof(ctx, "File system for container %s[%s] (address %s) successfully mounted%s at %q", workload, container, podAddrPort, roTxt, clientMountPoint)
return nil
}

// Assign a new address to the FTP client. This kills any open connections but leaves the FUSE driver intact
dlog.Infof(ctx, "Switching remote address to %s for FTP file system for workload container %s[%s] at %q", podAddrPort, workload, container, clientMountPoint)
return m.ftpClient.SetAddress(podAddrPort)
}
3 changes: 2 additions & 1 deletion pkg/client/userd/trafficmgr/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ func (pa *podAccess) startMount(ctx context.Context, iceptWG, podWG *sync.WaitGr
}
// The FTP mounter survives multiple starts for the same intercept. It just resets the address
mountCtx = pa.ctx
if fuseftp = userd.GetService(ctx).FuseFTPMgr().GetFuseFTPClient(ctx); fuseftp == nil {
fuseftp = userd.GetService(ctx).FuseFTPMgr().GetFuseFTPClient(ctx)
if fuseftp == nil {
dlog.Errorf(ctx, "Client is configured to perform remote mounts using FTP, but the fuseftp server was unable to start")
return
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/grpc/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ func Stop(ctx context.Context, svc *grpc.Server, maxTime time.Duration) {
// if the context has soft-cancel enabled. The server's Stop function will be called if no soft-cancel is enabled or
// when the GracefulStop doesn't finish until the Done channel of the hard context closed.
func Wait(ctx context.Context, svc *grpc.Server) {
<-ctx.Done()
hardCtx := dcontext.HardContext(ctx)
if hardCtx != ctx {
<-ctx.Done()
dead := make(chan struct{})
go func() {
dlog.Debug(ctx, "Initiating soft shutdown")
Expand Down

0 comments on commit 870c9f4

Please sign in to comment.