Skip to content

Commit

Permalink
[v15] Default BaseURL only for community / enterprise editions (#51934)
Browse files Browse the repository at this point in the history
* Default BaseURL only for community / enterprise editions (#51732)

* Add requirement to set base URL for OSS builds
Fix progress bar for darwin platform

* Show warning only before update

* Move error to teleportPackageURLs

* Move error to teleportPackageURLs

* Fix linter

* Fix setting modules build type for tsh and tctl (#51986)

* Fix setting modules for tsh and tctl

* Restore IsOSSBuild()

* Add different warning messages depending on whether the update is requested by the `webapi/find` response or set via an environment variable.

* Check only the build type of client tools
  • Loading branch information
vapopov authored Feb 11, 2025
1 parent 0cae0b9 commit aac343d
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 18 deletions.
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,14 @@ all: version
binaries:
$(MAKE) $(BINARIES)

# Appending new conditional settings for community build type for tools.
ifeq ("$(GITHUB_REPOSITORY_OWNER)","gravitational")
# TELEPORT_LDFLAGS and TOOLS_LDFLAGS if appended will overwrite the previous LDFLAGS set in the BUILDFLAGS.
# This is done here to prevent any changes to the (BUI)LDFLAGS passed to the other binaries
TELEPORT_LDFLAGS ?= -ldflags '$(GO_LDFLAGS) -X github.com/gravitational/teleport/lib/modules.teleportBuildType=community'
TOOLS_LDFLAGS ?= -ldflags '$(GO_LDFLAGS) -X github.com/gravitational/teleport/lib/modules.teleportBuildType=community'
endif

# By making these 3 targets below (tsh, tctl and teleport) PHONY we are solving
# several problems:
# * Build will rely on go build internal caching https://golang.org/doc/go1.10 at all times
Expand All @@ -325,7 +333,7 @@ $(BUILDDIR)/tctl:
@if [[ -z "$(LIBFIDO2_BUILD_TAG)" ]]; then \
echo 'Warning: Building tctl without libfido2. Install libfido2 to have access to MFA.' >&2; \
fi
GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -tags "$(PAM_TAG) $(FIPS_TAG) $(LIBFIDO2_BUILD_TAG) $(PIV_BUILD_TAG)" -o $(BUILDDIR)/tctl $(BUILDFLAGS) ./tool/tctl
GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -tags "$(PAM_TAG) $(FIPS_TAG) $(LIBFIDO2_BUILD_TAG) $(PIV_BUILD_TAG)" -o $(BUILDDIR)/tctl $(BUILDFLAGS) $(TOOLS_LDFLAGS) ./tool/tctl

.PHONY: $(BUILDDIR)/teleport
$(BUILDDIR)/teleport: ensure-webassets bpf-bytecode rdpclient
Expand All @@ -345,15 +353,15 @@ $(BUILDDIR)/tsh:
@if [[ -z "$(LIBFIDO2_BUILD_TAG)" ]]; then \
echo 'Warning: Building tsh without libfido2. Install libfido2 to have access to MFA.' >&2; \
fi
GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG_TSH) go build -tags "$(FIPS_TAG) $(LIBFIDO2_BUILD_TAG) $(TOUCHID_TAG) $(PIV_BUILD_TAG)" -o $(BUILDDIR)/tsh $(BUILDFLAGS) ./tool/tsh
GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG_TSH) go build -tags "$(FIPS_TAG) $(LIBFIDO2_BUILD_TAG) $(TOUCHID_TAG) $(PIV_BUILD_TAG)" -o $(BUILDDIR)/tsh $(BUILDFLAGS) $(TOOLS_LDFLAGS) ./tool/tsh

.PHONY: $(BUILDDIR)/tbot
# tbot is CGO-less by default except on Windows because lib/client/terminal/ wants CGO on this OS
$(BUILDDIR)/tbot: TBOT_CGO_FLAGS ?= $(if $(filter windows,$(OS)),$(CGOFLAG))
# Build mode pie requires CGO
$(BUILDDIR)/tbot: BUILDFLAGS_TBOT += $(if $(TBOT_CGO_FLAGS), -buildmode=pie)
$(BUILDDIR)/tbot:
GOOS=$(OS) GOARCH=$(ARCH) $(TBOT_CGO_FLAGS) go build -tags "$(FIPS_TAG)" -o $(BUILDDIR)/tbot $(BUILDFLAGS_TBOT) ./tool/tbot
GOOS=$(OS) GOARCH=$(ARCH) $(TBOT_CGO_FLAGS) go build -tags "$(FIPS_TAG)" -o $(BUILDDIR)/tbot $(BUILDFLAGS_TBOT) $(TOOLS_LDFLAGS) ./tool/tbot

.PHONY: $(BUILDDIR)/fdpass-teleport
$(BUILDDIR)/fdpass-teleport:
Expand Down Expand Up @@ -1653,7 +1661,7 @@ changelog:
# does not match version set it will fail to create a release. If tag doesn't exist it
# will also fail to create a release.
#
# For more information on release notes generation see:
# For more information on release notes generation see:
# https://github.com/gravitational/shared-workflows/tree/gus/release-notes/tools/release-notes#readme
.PHONY: create-github-release
create-github-release: LATEST = false
Expand Down
16 changes: 12 additions & 4 deletions integration/autoupdate/tools/updater/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"context"
"crypto"
"fmt"
"os"
"time"

"github.com/gravitational/trace"
Expand All @@ -34,8 +35,12 @@ import (
"github.com/gravitational/teleport/lib/tlsca"
)

// TestPassword is password generated during the test to login in test cluster.
const TestPassword = "UPDATER_TEST_PASSWORD"
const (
// TestPassword is env var used for setting password generated during the test to login in test cluster.
TestPassword = "UPDATER_TEST_PASSWORD"
// TestBuild is env var for setting test build type during the test.
TestBuild = "UPDATER_TEST_BUILD"
)

var (
version = teleport.Version
Expand All @@ -53,17 +58,20 @@ func (p *TestModules) GetSuggestedAccessLists(ctx context.Context, identity *tls

// BuildType returns build type (OSS or Enterprise)
func (p *TestModules) BuildType() string {
if build := os.Getenv(TestBuild); build != "" {
return build
}
return "CLI"
}

// IsEnterpriseBuild returns false for [TestModules].
func (p *TestModules) IsEnterpriseBuild() bool {
return false
return os.Getenv(TestBuild) == modules.BuildEnterprise
}

// IsOSSBuild returns false for [TestModules].
func (p *TestModules) IsOSSBuild() bool {
return false
return os.Getenv(TestBuild) == modules.BuildOSS
}

// LicenseExpiry returns the expiry date of the enterprise license, if applicable.
Expand Down
49 changes: 49 additions & 0 deletions integration/autoupdate/tools/updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ import (
"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integration/autoupdate/tools/updater"
"github.com/gravitational/teleport/lib/autoupdate"
"github.com/gravitational/teleport/lib/autoupdate/tools"
"github.com/gravitational/teleport/lib/modules"
)

var (
Expand Down Expand Up @@ -216,3 +219,49 @@ func TestUpdateInterruptSignal(t *testing.T) {
}
assert.Contains(t, output.String(), "Update progress:")
}

// TestUpdateForOSSBuild verifies the update logic for AGPL editions of Teleport requires
// base URL environment variable.
func TestUpdateForOSSBuild(t *testing.T) {
t.Setenv(types.HomeEnvVar, t.TempDir())
ctx := context.Background()

// Enable OSS build.
t.Setenv(updater.TestBuild, modules.BuildOSS)

// Fetch compiled test binary with updater logic and install to $TELEPORT_HOME.
updater := tools.NewUpdater(
toolsDir,
testVersions[0],
tools.WithBaseURL(baseURL),
)
err := updater.Update(ctx, testVersions[0])
require.NoError(t, err)

// Verify that requested update is ignored by OSS build and version wasn't updated.
cmd := exec.CommandContext(ctx, filepath.Join(toolsDir, "tsh"), "version")
cmd.Env = append(
os.Environ(),
fmt.Sprintf("%s=%s", teleportToolsVersion, testVersions[1]),
)
out, err := cmd.Output()
require.NoError(t, err)

matches := pattern.FindStringSubmatch(string(out))
require.Len(t, matches, 2)
require.Equal(t, testVersions[0], matches[1])

// Next update is set with the base URL env variable, must download new version.
t.Setenv(autoupdate.BaseURLEnvVar, baseURL)
cmd = exec.CommandContext(ctx, filepath.Join(toolsDir, "tsh"), "version")
cmd.Env = append(
os.Environ(),
fmt.Sprintf("%s=%s", teleportToolsVersion, testVersions[1]),
)
out, err = cmd.Output()
require.NoError(t, err)

matches = pattern.FindStringSubmatch(string(out))
require.Len(t, matches, 2)
require.Equal(t, testVersions[1], matches[1])
}
3 changes: 2 additions & 1 deletion lib/autoupdate/tools/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func CheckAndUpdateRemote(ctx context.Context, proxy string, insecure bool, reEx
slog.WarnContext(ctx, "Client tools update is disabled", "error", err)
return nil
}

// Overrides default base URL for custom CDN for downloading updates.
if envBaseURL := os.Getenv(autoupdate.BaseURLEnvVar); envBaseURL != "" {
baseURL = envBaseURL
Expand All @@ -110,7 +111,7 @@ func updateAndReExec(ctx context.Context, updater *Updater, toolsVersion string,
// is required if the user passed in the TELEPORT_TOOLS_VERSION
// explicitly.
err := updater.UpdateWithLock(ctxUpdate, toolsVersion)
if err != nil && !errors.Is(err, context.Canceled) {
if err != nil && !errors.Is(err, context.Canceled) && !errors.Is(err, errNoBaseURL) {
return trace.Wrap(err)
}

Expand Down
9 changes: 3 additions & 6 deletions lib/autoupdate/tools/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func (u *Updater) UpdateWithLock(ctx context.Context, updateToolsVersion string)
// with defined updater directory suffix.
func (u *Updater) Update(ctx context.Context, toolsVersion string) error {
// Get platform specific download URLs.
packages, err := teleportPackageURLs(u.uriTemplate, u.baseURL, toolsVersion)
packages, err := teleportPackageURLs(ctx, u.uriTemplate, u.baseURL, toolsVersion)
if err != nil {
return trace.Wrap(err)
}
Expand Down Expand Up @@ -409,11 +409,6 @@ func (u *Updater) downloadHash(ctx context.Context, url string) ([]byte, error)
// downloadArchive downloads the archive package by `url` and writes content to the writer interface,
// return calculated sha256 hash sum of the content.
func (u *Updater) downloadArchive(ctx context.Context, url string, f io.Writer) ([]byte, error) {
// Display a progress bar before initiating the update request to inform the user that
// an update is in progress, allowing them the option to cancel before actual response
// which might be delayed with slow internet connection or complete isolation to CDN.
pw, finish := newProgressWriter(10)
defer finish()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, trace.Wrap(err)
Expand All @@ -429,6 +424,8 @@ func (u *Updater) downloadArchive(ctx context.Context, url string, f io.Writer)
if resp.StatusCode != http.StatusOK {
return nil, trace.BadParameter("bad status when downloading archive: %v", resp.StatusCode)
}
pw, finish := newProgressWriter(10)
defer finish()

if resp.ContentLength != -1 {
if err := checkFreeSpace(u.toolsDir, uint64(resp.ContentLength)); err != nil {
Expand Down
15 changes: 12 additions & 3 deletions lib/autoupdate/tools/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"bytes"
"context"
"errors"
"log/slog"
"os"
"os/exec"
"path/filepath"
Expand All @@ -40,6 +41,8 @@ import (
"github.com/gravitational/teleport/lib/utils"
)

var errNoBaseURL = errors.New("baseURL is not defined")

// Dir returns the path to client tools in $TELEPORT_HOME/bin.
func Dir() (string, error) {
home := os.Getenv(types.HomeEnvVar)
Expand Down Expand Up @@ -126,10 +129,16 @@ type packageURL struct {
Optional bool
}

// teleportPackageURLs returns the URL for the Teleport archive to download.
func teleportPackageURLs(uriTmpl string, baseURL, version string) ([]packageURL, error) {
var flags autoupdate.InstallFlags
// teleportPackageURLs returns URLs for the Teleport archives to download.
func teleportPackageURLs(ctx context.Context, uriTmpl string, baseURL, version string) ([]packageURL, error) {
m := modules.GetModules()
envBaseURL := os.Getenv(autoupdate.BaseURLEnvVar)
if m.BuildType() == modules.BuildOSS && envBaseURL == "" {
slog.WarnContext(ctx, "Client tools updates are disabled as they are licensed under AGPL. To use Community Edition builds or custom binaries, set the 'TELEPORT_CDN_BASE_URL' environment variable.")
return nil, errNoBaseURL
}

var flags autoupdate.InstallFlags
if m.IsBoringBinary() {
flags |= autoupdate.FlagFIPS
}
Expand Down

0 comments on commit aac343d

Please sign in to comment.