Replace go-bindata with Go embed

Co-authored-by: nrwiersma <nick@wiersma.co.za>
This commit is contained in:
Antoine 2021-09-15 10:36:14 +02:00 committed by GitHub
parent 7ff13c3e3e
commit 70359e5d27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 142 additions and 205 deletions

View file

@ -24,7 +24,7 @@ jobs:
- name: Build webui
run: |
make generate-webui
tar czvf webui.tar.gz ./static/
tar czvf webui.tar.gz ./webui/static/
- name: Artifact webui
uses: actions/upload-artifact@v2
@ -66,9 +66,6 @@ jobs:
key: ${{ runner.os }}-build-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-build-go-
- name: Installing dependencies
run: go install github.com/containous/go-bindata/go-bindata@v1.0.0
- name: Artifact webui
uses: actions/download-artifact@v2
with:

View file

@ -39,8 +39,8 @@ jobs:
key: ${{ runner.os }}-test-unit-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-test-unit-go-
- name: Installing dependencies
run: go install github.com/containous/go-bindata/go-bindata@v1.0.0
- name: Avoid generating webui
run: mkdir -p webui/static && touch webui/static/index.html
- name: Tests
run: make test-unit

View file

@ -41,15 +41,15 @@ jobs:
key: ${{ runner.os }}-validate-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-validate-go-
- name: Installing dependencies
run: go install github.com/containous/go-bindata/go-bindata@v1.0.0
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }}
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}
- name: Install missspell ${{ env.MISSSPELL_VERSION }}
run: curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSSPELL_VERSION}
- name: Avoid generating webui
run: mkdir -p webui/static && touch webui/static/index.html
- name: Validate
run: make validate
@ -81,9 +81,6 @@ jobs:
key: ${{ runner.os }}-validate-generate-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-validate-generate-go-
- name: Installing dependencies
run: go install github.com/containous/go-bindata/go-bindata@v1.0.0
- name: go generate
run: |
go generate

3
.gitignore vendored
View file

@ -5,10 +5,9 @@
.DS_Store
/dist
/webui/.tmp/
/webui/static/
/site/
/docs/site/
/static/
/autogen/
/traefik
/traefik.toml
/traefik.yml

View file

@ -27,7 +27,6 @@ global_job_config:
- export GOPROXY=https://proxy.golang.org,direct
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.41.1
- curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
- go install github.com/containous/go-bindata/go-bindata@v1.0.0
- checkout
- cache restore traefik-$(checksum go.sum)
@ -41,7 +40,7 @@ blocks:
- name: Test Integration Container
commands:
- make pull-images
- mkdir -p static # Avoid to generate webui
- mkdir -p webui/static && touch webui/static/index.html # Avoid generating webui
- PRE_TARGET="" make binary
- make test-integration-container
- df -h
@ -61,7 +60,7 @@ blocks:
jobs:
- name: Test Integration Host
commands:
- mkdir -p static # Avoid to generate webui
- mkdir -p webui/static && touch webui/static/index.html # Avoid generating webui
- make test-integration-host
epilogue:
always:

View file

@ -59,12 +59,12 @@ build-webui-image:
## Generate WebUI
generate-webui:
if [ ! -d "static" ]; then \
if [ ! -d "webui/static" ]; then \
$(MAKE) build-webui-image; \
mkdir -p static; \
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui npm run build:nc; \
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui chown -R $(shell id -u):$(shell id -g) ../static; \
echo 'For more information show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
mkdir -p webui/static; \
docker run --rm -v "$$PWD/webui/static":'/src/webui/static' traefik-webui npm run build:nc; \
docker run --rm -v "$$PWD/webui/static":'/src/webui/static' traefik-webui chown -R $(shell id -u):$(shell id -g) ./static; \
echo 'For more information show `webui/readme.md`' > $$PWD/webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
fi
## Build the linux binary
@ -117,7 +117,7 @@ validate: $(PRE_TARGET)
## Clean up static directory and build a Docker Traefik image
build-image: binary
rm -rf static
rm -rf webui/static
docker build -t $(TRAEFIK_IMAGE) .
## Build a Docker Traefik image

View file

@ -13,11 +13,6 @@ RUN mkdir -p /usr/local/bin \
&& curl -fL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
# Download go-bindata binary to bin folder in $GOPATH
RUN mkdir -p /usr/local/bin \
&& curl -fsSL -o /usr/local/bin/go-bindata https://github.com/containous/go-bindata/releases/download/v1.0.0/go-bindata \
&& chmod +x /usr/local/bin/go-bindata
# Download golangci-lint binary to bin folder in $GOPATH
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.41.1

View file

@ -16,12 +16,10 @@ import (
"time"
"github.com/coreos/go-systemd/daemon"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/go-acme/lego/v4/challenge"
gokitmetrics "github.com/go-kit/kit/metrics"
"github.com/sirupsen/logrus"
"github.com/traefik/paerser/cli"
"github.com/traefik/traefik/v2/autogen/genstatic"
"github.com/traefik/traefik/v2/cmd"
"github.com/traefik/traefik/v2/cmd/healthcheck"
cmdVersion "github.com/traefik/traefik/v2/cmd/version"
@ -109,10 +107,6 @@ func runCmd(staticConfiguration *static.Configuration) error {
log.WithoutContext().Debugf("Static configuration loaded %s", string(jsonConf))
}
if staticConfiguration.API != nil && staticConfiguration.API.Dashboard {
staticConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"}
}
if staticConfiguration.Global.CheckNewVersion {
checkNewVersion()
}

View file

@ -64,7 +64,6 @@ Requirements:
- `go` v1.16+
- environment variable `GO111MODULE=on`
- [go-bindata](https://github.com/containous/go-bindata) `GO111MODULE=off go get -u github.com/containous/go-bindata/...`
!!! tip "Source Directory"
@ -101,18 +100,9 @@ Requirements:
Once you've set up your go environment and cloned the source repository, you can build Traefik.
Beforehand, you need to get [go-bindata](https://github.com/containous/go-bindata) (the first time) in order to be able to use the `go generate` command (which is part of the build process).
```bash
cd ~/go/src/github.com/traefik/traefik
# Get go-bindata. (Important: the ellipses are required.)
GO111MODULE=off go get github.com/containous/go-bindata/...
```
```bash
# Generate UI static files
rm -rf static/ autogen/; make generate-webui
rm -rf ./webui/static/; make generate-webui
# required to merge non-code components into the final binary,
# such as the web dashboard/UI

View file

@ -19,10 +19,6 @@ RUN apk --update upgrade \
&& update-ca-certificates \
&& rm -rf /var/cache/apk/*
RUN mkdir -p /usr/local/bin \
&& curl -fsSL -o /usr/local/bin/go-bindata https://github.com/containous/go-bindata/releases/download/v1.0.0/go-bindata \
&& chmod +x /usr/local/bin/go-bindata
WORKDIR /go/src/github.com/traefik/traefik
# Download go modules

View file

@ -1,7 +1,3 @@
//go:generate mkdir -p autogen
//go:generate rm -vf autogen/genstatic/gen.go
//go:generate mkdir -p static
//go:generate go-bindata -pkg genstatic -nocompress -o autogen/genstatic/gen.go ./static/...
//go:generate go run ./internal/
package main

1
go.mod
View file

@ -27,7 +27,6 @@ require (
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
github.com/eapache/channels v1.1.0
github.com/elazarl/go-bindata-assetfs v1.0.0
github.com/fatih/structs v1.1.0
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
github.com/go-acme/lego/v4 v4.4.0

2
go.sum
View file

@ -311,8 +311,6 @@ github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6
github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY=
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=

View file

@ -160,9 +160,7 @@ func reset(field reflect.Value, name string) error {
}
}
case reflect.Interface:
if !field.IsNil() {
return reset(field.Elem(), "")
}
return fmt.Errorf("reset not supported for interface type (for %s field)", name)
default:
// Primitive type
field.Set(reflect.Zero(field.Type()))

View file

@ -7,7 +7,6 @@ import (
"testing"
"time"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
@ -778,18 +777,6 @@ func TestDo_staticConfiguration(t *testing.T) {
Insecure: true,
Dashboard: true,
Debug: true,
DashboardAssets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return nil, nil
},
AssetDir: func(path string) ([]string, error) {
return nil, nil
},
AssetInfo: func(path string) (os.FileInfo, error) {
return nil, nil
},
Prefix: "fii",
},
}
config.Metrics = &types.Metrics{

View file

@ -1,59 +0,0 @@
package api
import (
"net/http"
"net/url"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/gorilla/mux"
"github.com/traefik/traefik/v2/pkg/log"
)
// DashboardHandler expose dashboard routes.
type DashboardHandler struct {
Assets *assetfs.AssetFS
}
// Append add dashboard routes on a router.
func (g DashboardHandler) Append(router *mux.Router) {
if g.Assets == nil {
log.WithoutContext().Error("No assets for dashboard")
return
}
// Expose dashboard
router.Methods(http.MethodGet).
Path("/").
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
http.Redirect(resp, req, safePrefix(req)+"/dashboard/", http.StatusFound)
})
router.Methods(http.MethodGet).
PathPrefix("/dashboard/").
Handler(http.StripPrefix("/dashboard/", http.FileServer(g.Assets)))
}
func (g DashboardHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// allow iframes from our domains only
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
http.FileServer(g.Assets).ServeHTTP(w, r)
}
func safePrefix(req *http.Request) string {
prefix := req.Header.Get("X-Forwarded-Prefix")
if prefix == "" {
return ""
}
parse, err := url.Parse(prefix)
if err != nil {
return ""
}
if parse.Host != "" {
return ""
}
return parse.Path
}

View file

@ -0,0 +1,68 @@
package dashboard
import (
"io/fs"
"net/http"
"net/url"
"github.com/gorilla/mux"
"github.com/traefik/traefik/v2/webui"
)
// Handler expose dashboard routes.
type Handler struct {
assets fs.FS // optional assets, to override the webui.FS default
}
// Append adds dashboard routes on the given router, optionally using the given
// assets (or webui.FS otherwise).
func Append(router *mux.Router, customAssets fs.FS) {
assets := customAssets
if assets == nil {
assets = webui.FS
}
// Expose dashboard
router.Methods(http.MethodGet).
Path("/").
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
http.Redirect(resp, req, safePrefix(req)+"/dashboard/", http.StatusFound)
})
router.Methods(http.MethodGet).
PathPrefix("/dashboard/").
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// allow iframes from our domains only
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
http.StripPrefix("/dashboard/", http.FileServer(http.FS(assets))).ServeHTTP(w, r)
})
}
func (g Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
assets := g.assets
if assets == nil {
assets = webui.FS
}
// allow iframes from our domains only
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
http.FileServer(http.FS(assets)).ServeHTTP(w, r)
}
func safePrefix(req *http.Request) string {
prefix := req.Header.Get("X-Forwarded-Prefix")
if prefix == "" {
return ""
}
parse, err := url.Parse(prefix)
if err != nil {
return ""
}
if parse.Host != "" {
return ""
}
return parse.Path
}

View file

@ -1,12 +1,14 @@
package api
package dashboard
import (
"fmt"
"errors"
"io/fs"
"net/http"
"net/http/httptest"
"testing"
"testing/fstest"
"time"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -59,48 +61,30 @@ func Test_safePrefix(t *testing.T) {
func Test_ContentSecurityPolicy(t *testing.T) {
testCases := []struct {
desc string
handler DashboardHandler
handler Handler
expected int
}{
{
desc: "OK",
handler: DashboardHandler{
Assets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return []byte{}, nil
},
AssetDir: func(path string) ([]string, error) {
return []string{}, nil
},
},
handler: Handler{
assets: fstest.MapFS{"foobar.html": &fstest.MapFile{
Mode: 0755,
ModTime: time.Now(),
}},
},
expected: http.StatusOK,
},
{
desc: "Not found",
handler: DashboardHandler{
Assets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return []byte{}, fmt.Errorf("not found")
},
AssetDir: func(path string) ([]string, error) {
return []string{}, fmt.Errorf("not found")
},
},
handler: Handler{
assets: fstest.MapFS{},
},
expected: http.StatusNotFound,
},
{
desc: "Internal server error",
handler: DashboardHandler{
Assets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return []byte{}, fmt.Errorf("oops")
},
AssetDir: func(path string) ([]string, error) {
return []string{}, fmt.Errorf("oops")
},
},
handler: Handler{
assets: errorFS{},
},
expected: http.StatusInternalServerError,
},
@ -122,3 +106,9 @@ func Test_ContentSecurityPolicy(t *testing.T) {
})
}
}
type errorFS struct{}
func (e errorFS) Open(name string) (fs.File, error) {
return nil, errors.New("oops")
}

View file

@ -6,7 +6,6 @@ import (
"reflect"
"strings"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/gorilla/mux"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/config/runtime"
@ -48,10 +47,7 @@ type RunTimeRepresentation struct {
// Handler serves the configuration and status of Traefik on API endpoints.
type Handler struct {
dashboard bool
debug bool
staticConfig static.Configuration
dashboardAssets *assetfs.AssetFS
staticConfig static.Configuration
// runtimeConfiguration is the data set used to create all the data representations exposed by the API.
runtimeConfiguration *runtime.Configuration
@ -73,11 +69,8 @@ func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration
}
return &Handler{
dashboard: staticConfig.API.Dashboard,
dashboardAssets: staticConfig.API.DashboardAssets,
runtimeConfiguration: rConfig,
staticConfig: staticConfig,
debug: staticConfig.API.Debug,
}
}
@ -85,7 +78,7 @@ func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration
func (h Handler) createRouter() *mux.Router {
router := mux.NewRouter()
if h.debug {
if h.staticConfig.API.Debug {
DebugHandler{}.Append(router)
}
@ -118,10 +111,6 @@ func (h Handler) createRouter() *mux.Router {
version.Handler{}.Append(router)
if h.dashboard {
DashboardHandler{Assets: h.dashboardAssets}.Append(router)
}
return router
}

View file

@ -6,7 +6,6 @@ import (
"strings"
"time"
assetfs "github.com/elazarl/go-bindata-assetfs"
legolog "github.com/go-acme/lego/v4/log"
"github.com/sirupsen/logrus"
ptypes "github.com/traefik/paerser/types"
@ -108,7 +107,6 @@ type API struct {
Debug bool `description:"Enable additional endpoints for debugging and profiling." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"`
// TODO: Re-enable statistics
// Statistics *types.Statistics `description:"Enable more detailed statistics." json:"statistics,omitempty" toml:"statistics,omitempty" yaml:"statistics,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
DashboardAssets *assetfs.AssetFS `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
}
// SetDefaults sets the default values.

View file

@ -3,7 +3,9 @@ package service
import (
"net/http"
"github.com/gorilla/mux"
"github.com/traefik/traefik/v2/pkg/api"
"github.com/traefik/traefik/v2/pkg/api/dashboard"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/metrics"
@ -36,10 +38,17 @@ func NewManagerFactory(staticConfiguration static.Configuration, routinesPool *s
}
if staticConfiguration.API != nil {
factory.api = api.NewBuilder(staticConfiguration)
apiRouterBuilder := api.NewBuilder(staticConfiguration)
if staticConfiguration.API.Dashboard {
factory.dashboardHandler = api.DashboardHandler{Assets: staticConfiguration.API.DashboardAssets}
factory.dashboardHandler = dashboard.Handler{}
factory.api = func(configuration *runtime.Configuration) http.Handler {
router := apiRouterBuilder(configuration).(*mux.Router)
dashboard.Append(router, nil)
return router
}
} else {
factory.api = apiRouterBuilder
}
}

View file

@ -1,11 +1,6 @@
#!/usr/bin/env bash
set -e
if ! test -e autogen/genstatic/gen.go; then
echo >&2 'error: generate must be run before binary'
false
fi
rm -f dist/traefik
FLAGS=()

View file

@ -1,11 +1,6 @@
#!/usr/bin/env bash
set -e
if ! test -e autogen/genstatic/gen.go; then
echo >&2 'error: generate must be run before crossbinary'
false
fi
if [ -z "$VERSION" ]; then
VERSION=$(git rev-parse HEAD)
fi

View file

@ -1,11 +1,6 @@
#!/usr/bin/env bash
set -e
if ! test -e autogen/genstatic/gen.go; then
echo >&2 'error: generate must be run before test-unit'
false
fi
RED=$'\033[31m'
GREEN=$'\033[32m'
TEXTRESET=$'\033[0m' # reset the foreground colour

View file

@ -4,9 +4,9 @@ const folder = process.argv[2]
async function execute () {
try {
await fs.emptyDir('../static')
await fs.emptyDir('./static')
console.log('Deleted static folder contents!')
await fs.copy(`./dist/${folder}`, '../static', { overwrite: true })
await fs.copy(`./dist/${folder}`, './static', { overwrite: true })
console.log('Installed new files in static folder!')
} catch (err) {
console.error(err)

12
webui/embed.go Normal file
View file

@ -0,0 +1,12 @@
package webui
import (
"embed"
"io/fs"
)
//go:embed static
var assets embed.FS
// FS contains the web UI assets.
var FS, _ = fs.Sub(assets, "static")

View file

@ -14,15 +14,15 @@ Traefik Web UI provide 2 types of information:
Use the make file :
```shell
make build # Generate Docker image
make generate-webui # Generate static contents in `traefik/static/` folder.
make build-image # Generate Docker image
make generate-webui # Generate static contents in `traefik/webui/static/` folder.
```
## How to build (only for frontend developer)
- prerequisite: [Node 12.11+](https://nodejs.org) [Npm](https://www.npmjs.com/)
- Go to the directory `webui`
- Go to the `webui` directory
- To install dependencies, execute the following commands:
@ -32,23 +32,23 @@ make generate-webui # Generate static contents in `traefik/static/` folder.
- `npm run build`
- Static contents are build in the directory `static`
- Static contents are built in the `webui/static` directory
**Don't change manually the files in the directory `static`**
**Do not manually change the files in the `webui/static` directory**
- The build allow to:
- The build allows to:
- optimize all JavaScript
- optimize all CSS
- add vendor prefixes to CSS (cross-bowser support)
- add a hash in the file names to prevent browser cache problems
- all images will be optimized at build
- optimize all images at build time
- bundle JavaScript in one file
## How to edit (only for frontend developer)
**Don't change manually the files in the directory `static`**
**Do not manually change the files in the `webui/static` directory**
- Go to the directory `webui`
- Go to the `webui` directory
- Edit files in `webui/src`
- Run in development mode :
- `npm run dev`