Replace go-bindata with Go embed
Co-authored-by: nrwiersma <nick@wiersma.co.za>
This commit is contained in:
parent
7ff13c3e3e
commit
70359e5d27
27 changed files with 142 additions and 205 deletions
5
.github/workflows/build.yaml
vendored
5
.github/workflows/build.yaml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
||||||
- name: Build webui
|
- name: Build webui
|
||||||
run: |
|
run: |
|
||||||
make generate-webui
|
make generate-webui
|
||||||
tar czvf webui.tar.gz ./static/
|
tar czvf webui.tar.gz ./webui/static/
|
||||||
|
|
||||||
- name: Artifact webui
|
- name: Artifact webui
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
@ -66,9 +66,6 @@ jobs:
|
||||||
key: ${{ runner.os }}-build-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-build-go-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: ${{ runner.os }}-build-go-
|
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
|
- name: Artifact webui
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
|
4
.github/workflows/test-unit.yaml
vendored
4
.github/workflows/test-unit.yaml
vendored
|
@ -39,8 +39,8 @@ jobs:
|
||||||
key: ${{ runner.os }}-test-unit-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-test-unit-go-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: ${{ runner.os }}-test-unit-go-
|
restore-keys: ${{ runner.os }}-test-unit-go-
|
||||||
|
|
||||||
- name: Installing dependencies
|
- name: Avoid generating webui
|
||||||
run: go install github.com/containous/go-bindata/go-bindata@v1.0.0
|
run: mkdir -p webui/static && touch webui/static/index.html
|
||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: make test-unit
|
run: make test-unit
|
||||||
|
|
9
.github/workflows/validate.yaml
vendored
9
.github/workflows/validate.yaml
vendored
|
@ -41,15 +41,15 @@ jobs:
|
||||||
key: ${{ runner.os }}-validate-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-validate-go-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: ${{ runner.os }}-validate-go-
|
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 }}
|
- 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}
|
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 }}
|
- 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}
|
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
|
- name: Validate
|
||||||
run: make validate
|
run: make validate
|
||||||
|
|
||||||
|
@ -81,9 +81,6 @@ jobs:
|
||||||
key: ${{ runner.os }}-validate-generate-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-validate-generate-go-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: ${{ runner.os }}-validate-generate-go-
|
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
|
- name: go generate
|
||||||
run: |
|
run: |
|
||||||
go generate
|
go generate
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -5,10 +5,9 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/dist
|
/dist
|
||||||
/webui/.tmp/
|
/webui/.tmp/
|
||||||
|
/webui/static/
|
||||||
/site/
|
/site/
|
||||||
/docs/site/
|
/docs/site/
|
||||||
/static/
|
|
||||||
/autogen/
|
|
||||||
/traefik
|
/traefik
|
||||||
/traefik.toml
|
/traefik.toml
|
||||||
/traefik.yml
|
/traefik.yml
|
||||||
|
|
|
@ -27,7 +27,6 @@ global_job_config:
|
||||||
- export GOPROXY=https://proxy.golang.org,direct
|
- 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 -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"
|
- 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
|
- checkout
|
||||||
- cache restore traefik-$(checksum go.sum)
|
- cache restore traefik-$(checksum go.sum)
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ blocks:
|
||||||
- name: Test Integration Container
|
- name: Test Integration Container
|
||||||
commands:
|
commands:
|
||||||
- make pull-images
|
- 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
|
- PRE_TARGET="" make binary
|
||||||
- make test-integration-container
|
- make test-integration-container
|
||||||
- df -h
|
- df -h
|
||||||
|
@ -61,7 +60,7 @@ blocks:
|
||||||
jobs:
|
jobs:
|
||||||
- name: Test Integration Host
|
- name: Test Integration Host
|
||||||
commands:
|
commands:
|
||||||
- mkdir -p static # Avoid to generate webui
|
- mkdir -p webui/static && touch webui/static/index.html # Avoid generating webui
|
||||||
- make test-integration-host
|
- make test-integration-host
|
||||||
epilogue:
|
epilogue:
|
||||||
always:
|
always:
|
||||||
|
|
12
Makefile
12
Makefile
|
@ -59,12 +59,12 @@ build-webui-image:
|
||||||
|
|
||||||
## Generate WebUI
|
## Generate WebUI
|
||||||
generate-webui:
|
generate-webui:
|
||||||
if [ ! -d "static" ]; then \
|
if [ ! -d "webui/static" ]; then \
|
||||||
$(MAKE) build-webui-image; \
|
$(MAKE) build-webui-image; \
|
||||||
mkdir -p static; \
|
mkdir -p webui/static; \
|
||||||
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui npm run build:nc; \
|
docker run --rm -v "$$PWD/webui/static":'/src/webui/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; \
|
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/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
|
echo 'For more information show `webui/readme.md`' > $$PWD/webui/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
## Build the linux binary
|
## Build the linux binary
|
||||||
|
@ -117,7 +117,7 @@ validate: $(PRE_TARGET)
|
||||||
|
|
||||||
## Clean up static directory and build a Docker Traefik image
|
## Clean up static directory and build a Docker Traefik image
|
||||||
build-image: binary
|
build-image: binary
|
||||||
rm -rf static
|
rm -rf webui/static
|
||||||
docker build -t $(TRAEFIK_IMAGE) .
|
docker build -t $(TRAEFIK_IMAGE) .
|
||||||
|
|
||||||
## Build a Docker Traefik image
|
## Build a Docker Traefik image
|
||||||
|
|
|
@ -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 \
|
&& curl -fL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \
|
||||||
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
|
| 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
|
# 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
|
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.41.1
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/go-systemd/daemon"
|
"github.com/coreos/go-systemd/daemon"
|
||||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
gokitmetrics "github.com/go-kit/kit/metrics"
|
gokitmetrics "github.com/go-kit/kit/metrics"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/traefik/paerser/cli"
|
"github.com/traefik/paerser/cli"
|
||||||
"github.com/traefik/traefik/v2/autogen/genstatic"
|
|
||||||
"github.com/traefik/traefik/v2/cmd"
|
"github.com/traefik/traefik/v2/cmd"
|
||||||
"github.com/traefik/traefik/v2/cmd/healthcheck"
|
"github.com/traefik/traefik/v2/cmd/healthcheck"
|
||||||
cmdVersion "github.com/traefik/traefik/v2/cmd/version"
|
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))
|
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 {
|
if staticConfiguration.Global.CheckNewVersion {
|
||||||
checkNewVersion()
|
checkNewVersion()
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ Requirements:
|
||||||
|
|
||||||
- `go` v1.16+
|
- `go` v1.16+
|
||||||
- environment variable `GO111MODULE=on`
|
- 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"
|
!!! 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.
|
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
|
```bash
|
||||||
# Generate UI static files
|
# 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,
|
# required to merge non-code components into the final binary,
|
||||||
# such as the web dashboard/UI
|
# such as the web dashboard/UI
|
||||||
|
|
|
@ -19,10 +19,6 @@ RUN apk --update upgrade \
|
||||||
&& update-ca-certificates \
|
&& update-ca-certificates \
|
||||||
&& rm -rf /var/cache/apk/*
|
&& 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
|
WORKDIR /go/src/github.com/traefik/traefik
|
||||||
|
|
||||||
# Download go modules
|
# Download go modules
|
||||||
|
|
|
@ -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/
|
//go:generate go run ./internal/
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -27,7 +27,6 @@ require (
|
||||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||||
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
|
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
|
||||||
github.com/eapache/channels v1.1.0
|
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/fatih/structs v1.1.0
|
||||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
||||||
github.com/go-acme/lego/v4 v4.4.0
|
github.com/go-acme/lego/v4 v4.4.0
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -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 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY=
|
||||||
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
|
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 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-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/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=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
|
|
|
@ -160,9 +160,7 @@ func reset(field reflect.Value, name string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
if !field.IsNil() {
|
return fmt.Errorf("reset not supported for interface type (for %s field)", name)
|
||||||
return reset(field.Elem(), "")
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// Primitive type
|
// Primitive type
|
||||||
field.Set(reflect.Zero(field.Type()))
|
field.Set(reflect.Zero(field.Type()))
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
ptypes "github.com/traefik/paerser/types"
|
ptypes "github.com/traefik/paerser/types"
|
||||||
|
@ -778,18 +777,6 @@ func TestDo_staticConfiguration(t *testing.T) {
|
||||||
Insecure: true,
|
Insecure: true,
|
||||||
Dashboard: true,
|
Dashboard: true,
|
||||||
Debug: 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{
|
config.Metrics = &types.Metrics{
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
68
pkg/api/dashboard/dashboard.go
Normal file
68
pkg/api/dashboard/dashboard.go
Normal 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
|
||||||
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
package api
|
package dashboard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"testing/fstest"
|
||||||
|
"time"
|
||||||
|
|
||||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -59,48 +61,30 @@ func Test_safePrefix(t *testing.T) {
|
||||||
func Test_ContentSecurityPolicy(t *testing.T) {
|
func Test_ContentSecurityPolicy(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
handler DashboardHandler
|
handler Handler
|
||||||
expected int
|
expected int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "OK",
|
desc: "OK",
|
||||||
handler: DashboardHandler{
|
handler: Handler{
|
||||||
Assets: &assetfs.AssetFS{
|
assets: fstest.MapFS{"foobar.html": &fstest.MapFile{
|
||||||
Asset: func(path string) ([]byte, error) {
|
Mode: 0755,
|
||||||
return []byte{}, nil
|
ModTime: time.Now(),
|
||||||
},
|
}},
|
||||||
AssetDir: func(path string) ([]string, error) {
|
|
||||||
return []string{}, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expected: http.StatusOK,
|
expected: http.StatusOK,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Not found",
|
desc: "Not found",
|
||||||
handler: DashboardHandler{
|
handler: Handler{
|
||||||
Assets: &assetfs.AssetFS{
|
assets: fstest.MapFS{},
|
||||||
Asset: func(path string) ([]byte, error) {
|
|
||||||
return []byte{}, fmt.Errorf("not found")
|
|
||||||
},
|
|
||||||
AssetDir: func(path string) ([]string, error) {
|
|
||||||
return []string{}, fmt.Errorf("not found")
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expected: http.StatusNotFound,
|
expected: http.StatusNotFound,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Internal server error",
|
desc: "Internal server error",
|
||||||
handler: DashboardHandler{
|
handler: Handler{
|
||||||
Assets: &assetfs.AssetFS{
|
assets: errorFS{},
|
||||||
Asset: func(path string) ([]byte, error) {
|
|
||||||
return []byte{}, fmt.Errorf("oops")
|
|
||||||
},
|
|
||||||
AssetDir: func(path string) ([]string, error) {
|
|
||||||
return []string{}, fmt.Errorf("oops")
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expected: http.StatusInternalServerError,
|
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")
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/traefik/traefik/v2/pkg/config/runtime"
|
"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.
|
// Handler serves the configuration and status of Traefik on API endpoints.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
dashboard bool
|
|
||||||
debug bool
|
|
||||||
staticConfig static.Configuration
|
staticConfig static.Configuration
|
||||||
dashboardAssets *assetfs.AssetFS
|
|
||||||
|
|
||||||
// runtimeConfiguration is the data set used to create all the data representations exposed by the API.
|
// runtimeConfiguration is the data set used to create all the data representations exposed by the API.
|
||||||
runtimeConfiguration *runtime.Configuration
|
runtimeConfiguration *runtime.Configuration
|
||||||
|
@ -73,11 +69,8 @@ func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
dashboard: staticConfig.API.Dashboard,
|
|
||||||
dashboardAssets: staticConfig.API.DashboardAssets,
|
|
||||||
runtimeConfiguration: rConfig,
|
runtimeConfiguration: rConfig,
|
||||||
staticConfig: staticConfig,
|
staticConfig: staticConfig,
|
||||||
debug: staticConfig.API.Debug,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +78,7 @@ func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration
|
||||||
func (h Handler) createRouter() *mux.Router {
|
func (h Handler) createRouter() *mux.Router {
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
if h.debug {
|
if h.staticConfig.API.Debug {
|
||||||
DebugHandler{}.Append(router)
|
DebugHandler{}.Append(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,10 +111,6 @@ func (h Handler) createRouter() *mux.Router {
|
||||||
|
|
||||||
version.Handler{}.Append(router)
|
version.Handler{}.Append(router)
|
||||||
|
|
||||||
if h.dashboard {
|
|
||||||
DashboardHandler{Assets: h.dashboardAssets}.Append(router)
|
|
||||||
}
|
|
||||||
|
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
|
||||||
legolog "github.com/go-acme/lego/v4/log"
|
legolog "github.com/go-acme/lego/v4/log"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
ptypes "github.com/traefik/paerser/types"
|
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"`
|
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
|
// 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"`
|
// 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.
|
// SetDefaults sets the default values.
|
||||||
|
|
|
@ -3,7 +3,9 @@ package service
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
"github.com/traefik/traefik/v2/pkg/api"
|
"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/runtime"
|
||||||
"github.com/traefik/traefik/v2/pkg/config/static"
|
"github.com/traefik/traefik/v2/pkg/config/static"
|
||||||
"github.com/traefik/traefik/v2/pkg/metrics"
|
"github.com/traefik/traefik/v2/pkg/metrics"
|
||||||
|
@ -36,10 +38,17 @@ func NewManagerFactory(staticConfiguration static.Configuration, routinesPool *s
|
||||||
}
|
}
|
||||||
|
|
||||||
if staticConfiguration.API != nil {
|
if staticConfiguration.API != nil {
|
||||||
factory.api = api.NewBuilder(staticConfiguration)
|
apiRouterBuilder := api.NewBuilder(staticConfiguration)
|
||||||
|
|
||||||
if staticConfiguration.API.Dashboard {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
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
|
rm -f dist/traefik
|
||||||
|
|
||||||
FLAGS=()
|
FLAGS=()
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
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
|
if [ -z "$VERSION" ]; then
|
||||||
VERSION=$(git rev-parse HEAD)
|
VERSION=$(git rev-parse HEAD)
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
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'
|
RED=$'\033[31m'
|
||||||
GREEN=$'\033[32m'
|
GREEN=$'\033[32m'
|
||||||
TEXTRESET=$'\033[0m' # reset the foreground colour
|
TEXTRESET=$'\033[0m' # reset the foreground colour
|
||||||
|
|
|
@ -4,9 +4,9 @@ const folder = process.argv[2]
|
||||||
|
|
||||||
async function execute () {
|
async function execute () {
|
||||||
try {
|
try {
|
||||||
await fs.emptyDir('../static')
|
await fs.emptyDir('./static')
|
||||||
console.log('Deleted static folder contents!')
|
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!')
|
console.log('Installed new files in static folder!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|
12
webui/embed.go
Normal file
12
webui/embed.go
Normal 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")
|
|
@ -14,15 +14,15 @@ Traefik Web UI provide 2 types of information:
|
||||||
Use the make file :
|
Use the make file :
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
make build # Generate Docker image
|
make build-image # Generate Docker image
|
||||||
make generate-webui # Generate static contents in `traefik/static/` folder.
|
make generate-webui # Generate static contents in `traefik/webui/static/` folder.
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to build (only for frontend developer)
|
## How to build (only for frontend developer)
|
||||||
|
|
||||||
- prerequisite: [Node 12.11+](https://nodejs.org) [Npm](https://www.npmjs.com/)
|
- 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:
|
- To install dependencies, execute the following commands:
|
||||||
|
|
||||||
|
@ -32,23 +32,23 @@ make generate-webui # Generate static contents in `traefik/static/` folder.
|
||||||
|
|
||||||
- `npm run build`
|
- `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 JavaScript
|
||||||
- optimize all CSS
|
- optimize all CSS
|
||||||
- add vendor prefixes to CSS (cross-bowser support)
|
- add vendor prefixes to CSS (cross-bowser support)
|
||||||
- add a hash in the file names to prevent browser cache problems
|
- 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
|
- bundle JavaScript in one file
|
||||||
|
|
||||||
## How to edit (only for frontend developer)
|
## 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`
|
- Edit files in `webui/src`
|
||||||
- Run in development mode :
|
- Run in development mode :
|
||||||
- `npm run dev`
|
- `npm run dev`
|
||||||
|
|
Loading…
Reference in a new issue