Better webassets embedding (#17058)

This commit is contained in:
Edoardo Spadolini
2022-10-06 08:36:23 +00:00
committed by GitHub
parent 7a486ff730
commit aeb6f1d2e5
8 changed files with 60 additions and 133 deletions
+4 -24
View File
@@ -26,7 +26,6 @@ ifneq ("$(wildcard /bin/bash)","")
SHELL := /bin/bash -o pipefail
endif
BUILDDIR ?= build
ASSETS_BUILDDIR ?= lib/web/build
BINDIR ?= /usr/local/bin
DATADIR ?= /usr/local/share/teleport
ADDFLAGS ?=
@@ -102,7 +101,7 @@ endif
# Check if rust and cargo are installed before compiling
CHECK_CARGO := $(shell cargo --version 2>/dev/null)
CHECK_RUST := $(shell rustc --version 2>/dev/null)
with_rdpclient := no
RDPCLIENT_MESSAGE := without-Windows-RDP-client
@@ -343,7 +342,7 @@ endif
# only tsh is built.
#
.PHONY:full
full: $(ASSETS_BUILDDIR)/webassets
full: ensure-webassets
ifneq ("$(OS)", "windows")
$(MAKE) all WEBASSETS_TAG="webassets_embed"
endif
@@ -354,9 +353,7 @@ endif
.PHONY:full-ent
full-ent:
ifneq ("$(OS)", "windows")
@if [ -f e/Makefile ]; then \
rm $(ASSETS_BUILDDIR)/webassets; \
$(MAKE) -C e full; fi
@if [ -f e/Makefile ]; then $(MAKE) -C e full; fi
endif
#
@@ -428,10 +425,7 @@ release-unix: clean full
tar $(TAR_FLAGS) -c teleport | gzip -n > $(RELEASE).tar.gz
rm -rf teleport
@echo "---> Created $(RELEASE).tar.gz."
@if [ -f e/Makefile ]; then \
rm -fr $(ASSETS_BUILDDIR)/webassets; \
$(MAKE) -C e release; \
fi
@if [ -f e/Makefile ]; then $(MAKE) -C e release; fi
#
# make release-windows-unsigned - Produces a binary release archive containing only tsh.
@@ -854,20 +848,6 @@ update-tag:
git tag api/$(GITTAG)
git push origin $(GITTAG) && git push origin api/$(GITTAG)
# build/webassets directory contains the web assets (UI) which get
# embedded in the teleport binary
$(ASSETS_BUILDDIR)/webassets: ensure-webassets $(ASSETS_BUILDDIR)
ifneq ("$(OS)", "windows")
@echo "---> Copying OSS web assets."; \
rm -rf $(ASSETS_BUILDDIR)/webassets; \
mkdir $(ASSETS_BUILDDIR)/webassets; \
cd webassets/teleport/ ; cp -r . ../../$@
endif
$(ASSETS_BUILDDIR):
mkdir -p $@
.PHONY: test-package
test-package: remove-temp-files
go test -v ./$(p)
+1 -1
Submodule e updated: 9a98dc59d5...93a19fd5ed
+2 -2
View File
@@ -4798,8 +4798,8 @@ func getPublicAddr(authClient auth.ReadAppsAccessPoint, a App) (string, error) {
// It uses external configuration to make the decision
func newHTTPFileSystem() (http.FileSystem, error) {
if !isDebugMode() {
fs, err := web.NewStaticFileSystem() //nolint:staticcheck
if err != nil { //nolint:staticcheck
fs, err := teleport.NewWebAssetsFilesystem() //nolint:staticcheck
if err != nil { //nolint:staticcheck
return nil, trace.Wrap(err)
}
return fs, nil
-30
View File
@@ -68,36 +68,6 @@ func executableFolder() (string, error) {
return filepath.Dir(filepath.Clean(p)), nil
}
const (
webAssetsMissingError = "the teleport binary was built without web assets, try building with `make release`"
webAssetsReadError = "failure reading web assets from the binary"
)
func readZipArchive(r io.ReaderAt, size int64) (ResourceMap, error) {
zreader, err := zip.NewReader(r, size)
if err != nil {
// this often happens when teleport is launched without the web assets
// zip file attached to the binary. for launching it in such mode
// set DEBUG environment variable to 1
if err == zip.ErrFormat {
return nil, trace.NotFound(webAssetsMissingError)
}
return nil, trace.NotFound("%s %v", webAssetsReadError, err)
}
entries := make(ResourceMap)
for _, file := range zreader.File {
if file.FileInfo().IsDir() {
continue
}
entries[file.Name] = file
}
// no entries found?
if len(entries) == 0 {
return nil, trace.Wrap(os.ErrInvalid)
}
return entries, nil
}
// resource struct implements http.File interface on top of zip.File object
type resource struct {
reader io.ReadCloser
-63
View File
@@ -18,11 +18,9 @@ package web
import (
"io"
"os"
"strings"
"testing"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
)
@@ -43,64 +41,3 @@ func TestLocalFS(t *testing.T) {
require.Equal(t, strings.Contains(html, `<script src="/web/config.js"></script>`), true)
require.Equal(t, strings.Contains(html, `content="{{ .XCSRF }}"`), true)
}
func TestZipFS(t *testing.T) {
t.Parallel()
fs, err := readZipArchiveAt("../../fixtures/assets.zip")
require.NoError(t, err)
require.NotNil(t, fs)
// test simple full read:
f, err := fs.Open("/index.html")
require.NoError(t, err)
bytes, err := io.ReadAll(f)
require.NoError(t, err)
require.Equal(t, len(bytes), 813)
require.NoError(t, f.Close())
// seek + read
f, err = fs.Open("/index.html")
require.NoError(t, err)
defer f.Close()
n, err := f.Seek(10, io.SeekStart)
require.NoError(t, err)
require.Equal(t, n, int64(10))
bytes, err = io.ReadAll(f)
require.NoError(t, err)
require.Equal(t, len(bytes), 803)
n, err = f.Seek(-50, io.SeekEnd)
require.NoError(t, err)
require.Equal(t, n, int64(763))
bytes, err = io.ReadAll(f)
require.NoError(t, err)
require.Equal(t, len(bytes), 50)
_, err = f.Seek(-50, io.SeekEnd)
require.NoError(t, err)
n, err = f.Seek(-50, io.SeekCurrent)
require.NoError(t, err)
require.Equal(t, n, int64(713))
bytes, err = io.ReadAll(f)
require.NoError(t, err)
require.Equal(t, len(bytes), 100)
}
func readZipArchiveAt(path string) (ResourceMap, error) {
file, err := os.Open(path)
if err != nil {
return nil, trace.Wrap(err)
}
// file needs to stay open for http.FileSystem reads to work
//
// feed the binary into the zip reader and enumerate all files
// found in the attached zip file:
info, err := file.Stat()
if err != nil {
return nil, trace.Wrap(err)
}
return readZipArchive(file, info.Size())
}
@@ -1,5 +1,4 @@
//go:build webassets_embed
// +build webassets_embed
//go:build webassets_embed && !webassets_ent
/*
Copyright 2021 Gravitational, Inc.
@@ -17,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package web
package teleport
import (
"embed"
@@ -27,13 +26,13 @@ import (
"github.com/gravitational/trace"
)
//go:embed build/webassets
var webassetFS embed.FS
//go:embed webassets/teleport
var embedded embed.FS
// NewStaticFileSystem returns the initialized implementation of http.FileSystem
// interface which can be used to serve Teleport Proxy Web UI
func NewStaticFileSystem() (http.FileSystem, error) {
wfs, err := fs.Sub(webassetFS, "build/webassets")
// NewWebAssetsFilesystem returns the initialized implementation of
// http.FileSystem interface which can be used to serve Teleport Proxy Web UI
func NewWebAssetsFilesystem() (http.FileSystem, error) {
wfs, err := fs.Sub(embedded, "webassets/teleport")
if err != nil {
return nil, trace.Wrap(err)
}
+40
View File
@@ -0,0 +1,40 @@
//go:build webassets_embed && webassets_ent
/*
Copyright 2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package teleport
import (
"embed"
"io/fs"
"net/http"
"github.com/gravitational/trace"
)
//go:embed webassets/e/teleport
var embedded embed.FS
// NewWebAssetsFilesystem returns the initialized implementation of
// http.FileSystem interface which can be used to serve Teleport Proxy Web UI
func NewWebAssetsFilesystem() (http.FileSystem, error) {
wfs, err := fs.Sub(embedded, "webassets/e/teleport")
if err != nil {
return nil, trace.Wrap(err)
}
return http.FS(wfs), nil
}
+5 -4
View File
@@ -1,5 +1,4 @@
//go:build !webassets_embed
// +build !webassets_embed
/*
Copyright 2021 Gravitational, Inc.
@@ -17,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package web
package teleport
import (
"net/http"
@@ -25,7 +24,9 @@ import (
"github.com/gravitational/trace"
)
// NewStaticFileSystem is a no-op in this build mode.
func NewStaticFileSystem() (http.FileSystem, error) { //nolint:staticcheck
const webAssetsMissingError = "the teleport binary was built without web assets, try building with `make release`"
// NewWebAssetsFilesystem is a no-op in this build mode.
func NewWebAssetsFilesystem() (http.FileSystem, error) { //nolint:staticcheck
return nil, trace.NotFound(webAssetsMissingError)
}