Merge pull request #1543 from hashicorp/f-ui-static
Static asset compilation for Consul UI
This commit is contained in:
commit
b3a829589b
12
Makefile
12
Makefile
|
@ -1,4 +1,5 @@
|
||||||
GOTOOLS = github.com/mitchellh/gox golang.org/x/tools/cmd/stringer
|
GOTOOLS = github.com/mitchellh/gox golang.org/x/tools/cmd/stringer \
|
||||||
|
github.com/jteeuwen/go-bindata/... github.com/elazarl/go-bindata-assetfs/...
|
||||||
DEPS = $(shell go list -f '{{range .TestImports}}{{.}} {{end}}' ./...)
|
DEPS = $(shell go list -f '{{range .TestImports}}{{.}} {{end}}' ./...)
|
||||||
PACKAGES = $(shell go list ./...)
|
PACKAGES = $(shell go list ./...)
|
||||||
VETARGS?=-asmdecl -atomic -bool -buildtags -copylocks -methods \
|
VETARGS?=-asmdecl -atomic -bool -buildtags -copylocks -methods \
|
||||||
|
@ -68,10 +69,17 @@ generate: deps
|
||||||
find . -type f -name '.DS_Store' -delete
|
find . -type f -name '.DS_Store' -delete
|
||||||
go generate ./...
|
go generate ./...
|
||||||
|
|
||||||
|
# generates the static web ui
|
||||||
|
static-assets: deps
|
||||||
|
@echo "--> Generating static assets"
|
||||||
|
@go-bindata-assetfs -pkg agent -prefix ui ./ui/dist/...
|
||||||
|
@mv bindata_assetfs.go command/agent
|
||||||
|
$(MAKE) format
|
||||||
|
|
||||||
web:
|
web:
|
||||||
./scripts/website_run.sh
|
./scripts/website_run.sh
|
||||||
|
|
||||||
web-push:
|
web-push:
|
||||||
./scripts/website_push.sh
|
./scripts/website_push.sh
|
||||||
|
|
||||||
.PHONY: all bin dev dist cov deps test vet web web-push generate test-nodep
|
.PHONY: all bin dev dist cov deps test vet web web-push generate test-nodep static-assets
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -71,6 +71,7 @@ func (c *Command) readConfig() *Config {
|
||||||
cmdFlags.StringVar(&cmdConfig.NodeName, "node", "", "node name")
|
cmdFlags.StringVar(&cmdConfig.NodeName, "node", "", "node name")
|
||||||
cmdFlags.StringVar(&cmdConfig.Datacenter, "dc", "", "node datacenter")
|
cmdFlags.StringVar(&cmdConfig.Datacenter, "dc", "", "node datacenter")
|
||||||
cmdFlags.StringVar(&cmdConfig.DataDir, "data-dir", "", "path to the data directory")
|
cmdFlags.StringVar(&cmdConfig.DataDir, "data-dir", "", "path to the data directory")
|
||||||
|
cmdFlags.BoolVar(&cmdConfig.EnableUi, "ui", false, "enable the built-in web UI")
|
||||||
cmdFlags.StringVar(&cmdConfig.UiDir, "ui-dir", "", "path to the web UI directory")
|
cmdFlags.StringVar(&cmdConfig.UiDir, "ui-dir", "", "path to the web UI directory")
|
||||||
cmdFlags.StringVar(&cmdConfig.PidFile, "pid-file", "", "path to file to store PID")
|
cmdFlags.StringVar(&cmdConfig.PidFile, "pid-file", "", "path to file to store PID")
|
||||||
cmdFlags.StringVar(&cmdConfig.EncryptKey, "encrypt", "", "gossip encryption key")
|
cmdFlags.StringVar(&cmdConfig.EncryptKey, "encrypt", "", "gossip encryption key")
|
||||||
|
@ -990,6 +991,7 @@ Options:
|
||||||
-rejoin Ignores a previous leave and attempts to rejoin the cluster.
|
-rejoin Ignores a previous leave and attempts to rejoin the cluster.
|
||||||
-server Switches agent to server mode.
|
-server Switches agent to server mode.
|
||||||
-syslog Enables logging to syslog
|
-syslog Enables logging to syslog
|
||||||
|
-ui Enables the built-in static web UI server
|
||||||
-ui-dir=path Path to directory containing the Web UI resources
|
-ui-dir=path Path to directory containing the Web UI resources
|
||||||
-pid-file=path Path to file to store agent PID
|
-pid-file=path Path to file to store agent PID
|
||||||
|
|
||||||
|
|
|
@ -270,6 +270,10 @@ type Config struct {
|
||||||
RetryIntervalWan time.Duration `mapstructure:"-" json:"-"`
|
RetryIntervalWan time.Duration `mapstructure:"-" json:"-"`
|
||||||
RetryIntervalWanRaw string `mapstructure:"retry_interval_wan"`
|
RetryIntervalWanRaw string `mapstructure:"retry_interval_wan"`
|
||||||
|
|
||||||
|
// EnableUi enables the statically-compiled assets for the Consul web UI and
|
||||||
|
// serves them at the default /ui/ endpoint automatically.
|
||||||
|
EnableUi bool `mapstructure:"ui"`
|
||||||
|
|
||||||
// UiDir is the directory containing the Web UI resources.
|
// UiDir is the directory containing the Web UI resources.
|
||||||
// If provided, the UI endpoints will be enabled.
|
// If provided, the UI endpoints will be enabled.
|
||||||
UiDir string `mapstructure:"ui_dir"`
|
UiDir string `mapstructure:"ui_dir"`
|
||||||
|
@ -1004,6 +1008,9 @@ func MergeConfig(a, b *Config) *Config {
|
||||||
if b.Addresses.RPC != "" {
|
if b.Addresses.RPC != "" {
|
||||||
result.Addresses.RPC = b.Addresses.RPC
|
result.Addresses.RPC = b.Addresses.RPC
|
||||||
}
|
}
|
||||||
|
if b.EnableUi {
|
||||||
|
result.EnableUi = true
|
||||||
|
}
|
||||||
if b.UiDir != "" {
|
if b.UiDir != "" {
|
||||||
result.UiDir = b.UiDir
|
result.UiDir = b.UiDir
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,6 +441,17 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Static UI server
|
||||||
|
input = `{"ui": true}`
|
||||||
|
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.EnableUi {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
|
||||||
// UI Dir
|
// UI Dir
|
||||||
input = `{"ui_dir": "/opt/consul-ui"}`
|
input = `{"ui_dir": "/opt/consul-ui"}`
|
||||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||||
|
@ -1230,6 +1241,7 @@ func TestMergeConfig(t *testing.T) {
|
||||||
Services: []*ServiceDefinition{nil},
|
Services: []*ServiceDefinition{nil},
|
||||||
StartJoin: []string{"1.1.1.1"},
|
StartJoin: []string{"1.1.1.1"},
|
||||||
StartJoinWan: []string{"1.1.1.1"},
|
StartJoinWan: []string{"1.1.1.1"},
|
||||||
|
EnableUi: true,
|
||||||
UiDir: "/opt/consul-ui",
|
UiDir: "/opt/consul-ui",
|
||||||
EnableSyslog: true,
|
EnableSyslog: true,
|
||||||
RejoinAfterLeave: true,
|
RejoinAfterLeave: true,
|
||||||
|
|
|
@ -275,10 +275,11 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) {
|
||||||
s.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
s.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the UI + special endpoints
|
// Use the custom UI dir if provided.
|
||||||
if s.uiDir != "" {
|
if s.uiDir != "" {
|
||||||
// Static file serving done from /ui/
|
|
||||||
s.mux.Handle("/ui/", http.StripPrefix("/ui/", http.FileServer(http.Dir(s.uiDir))))
|
s.mux.Handle("/ui/", http.StripPrefix("/ui/", http.FileServer(http.Dir(s.uiDir))))
|
||||||
|
} else if s.agent.config.EnableUi {
|
||||||
|
s.mux.Handle("/ui/", http.StripPrefix("/ui/", http.FileServer(assetFS())))
|
||||||
}
|
}
|
||||||
|
|
||||||
// API's are under /internal/ui/ to avoid conflict
|
// API's are under /internal/ui/ to avoid conflict
|
||||||
|
|
|
@ -34,11 +34,6 @@ func makeHTTPServerWithConfig(t *testing.T, cb func(c *Config)) (string, *HTTPSe
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, agent := makeAgent(t, conf)
|
dir, agent := makeAgent(t, conf)
|
||||||
uiDir := filepath.Join(dir, "ui")
|
|
||||||
if err := os.Mkdir(uiDir, 755); err != nil {
|
|
||||||
t.Fatalf("err: %v", err)
|
|
||||||
}
|
|
||||||
conf.UiDir = uiDir
|
|
||||||
servers, err := NewHTTPServers(agent, conf, agent.logOutput)
|
servers, err := NewHTTPServers(agent, conf, agent.logOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
|
@ -635,6 +630,26 @@ func TestScadaHTTP(t *testing.T) {
|
||||||
scadaHttp.mux.HandleFunc("/debug/pprof/symbol", mockFn)
|
scadaHttp.mux.HandleFunc("/debug/pprof/symbol", mockFn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnableWebUI(t *testing.T) {
|
||||||
|
httpTestWithConfig(t, func(s *HTTPServer) {
|
||||||
|
req, err := http.NewRequest("GET", "/ui/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the request
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
s.mux.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
// Check the result
|
||||||
|
if resp.Code != 200 {
|
||||||
|
t.Fatalf("should handle ui")
|
||||||
|
}
|
||||||
|
}, func(c *Config) {
|
||||||
|
c.EnableUi = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// assertIndex tests that X-Consul-Index is set and non-zero
|
// assertIndex tests that X-Consul-Index is set and non-zero
|
||||||
func assertIndex(t *testing.T, resp *httptest.ResponseRecorder) {
|
func assertIndex(t *testing.T, resp *httptest.ResponseRecorder) {
|
||||||
header := resp.Header().Get("X-Consul-Index")
|
header := resp.Header().Get("X-Consul-Index")
|
||||||
|
|
|
@ -18,7 +18,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUiIndex(t *testing.T) {
|
func TestUiIndex(t *testing.T) {
|
||||||
dir, srv := makeHTTPServer(t)
|
// Make a test dir to serve UI files
|
||||||
|
uiDir, err := ioutil.TempDir("", "consul")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(uiDir)
|
||||||
|
|
||||||
|
// Make the server
|
||||||
|
dir, srv := makeHTTPServerWithConfig(t, func(c *Config) {
|
||||||
|
c.UiDir = uiDir
|
||||||
|
})
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
defer srv.Shutdown()
|
defer srv.Shutdown()
|
||||||
defer srv.agent.Shutdown()
|
defer srv.agent.Shutdown()
|
||||||
|
|
17
ui/README.md
17
ui/README.md
|
@ -60,3 +60,20 @@ The `dist` folder will contain the files you should use for deployment.
|
||||||
|
|
||||||
###Acknowledgements
|
###Acknowledgements
|
||||||
cog icon by useiconic.com from the [Noun Project](https://thenounproject.com/term/setting/45865/)
|
cog icon by useiconic.com from the [Noun Project](https://thenounproject.com/term/setting/45865/)
|
||||||
|
|
||||||
|
### Compiling the UI into the Go binary
|
||||||
|
|
||||||
|
The UI is compiled and shipped with the Consul go binary. The generated bindata
|
||||||
|
file lives in the `command/agent/bindata_assetfs.go` file and is checked into
|
||||||
|
source control. This is useful so that not every Consul developer needs to set
|
||||||
|
up bundler etc. To re-generate the file, first follow the compilation steps
|
||||||
|
above to build the UI assets into the `dist/` folder. With that done, from the
|
||||||
|
root of the Consul repo, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ make static-assets
|
||||||
|
```
|
||||||
|
|
||||||
|
The file will now be refreshed with the current UI data. You can now rebuild the
|
||||||
|
Consul binary normally with `make bin` or `make dev`, and see the updated UI
|
||||||
|
after re-launching Consul.
|
||||||
|
|
|
@ -228,8 +228,12 @@ The options below are all specified on the command-line.
|
||||||
* <a name="_syslog"></a><a href="#_syslog">`-syslog`</a> - This flag enables logging to syslog. This
|
* <a name="_syslog"></a><a href="#_syslog">`-syslog`</a> - This flag enables logging to syslog. This
|
||||||
is only supported on Linux and OSX. It will result in an error if provided on Windows.
|
is only supported on Linux and OSX. It will result in an error if provided on Windows.
|
||||||
|
|
||||||
|
* <a name="_ui"></a><a href="#_ui">`-ui`</a> - Enables the built-in web UI
|
||||||
|
server and the required HTTP routes. This eliminates the need to maintain the
|
||||||
|
Consul web UI files separately from the binary.
|
||||||
|
|
||||||
* <a name="_ui_dir"></a><a href="#_ui_dir">`-ui-dir`</a> - This flag provides the directory containing
|
* <a name="_ui_dir"></a><a href="#_ui_dir">`-ui-dir`</a> - This flag provides the directory containing
|
||||||
the Web UI resources for Consul. This must be provided to enable the Web UI. The directory must be
|
the Web UI resources for Consul. This will automatically enable the Web UI. The directory must be
|
||||||
readable to the agent.
|
readable to the agent.
|
||||||
|
|
||||||
## <a name="configuration_files"></a>Configuration Files
|
## <a name="configuration_files"></a>Configuration Files
|
||||||
|
@ -590,6 +594,9 @@ definitions support being updated during a reload.
|
||||||
[`enable_syslog`](#enable_syslog) is provided, this controls to which
|
[`enable_syslog`](#enable_syslog) is provided, this controls to which
|
||||||
facility messages are sent. By default, `LOCAL0` will be used.
|
facility messages are sent. By default, `LOCAL0` will be used.
|
||||||
|
|
||||||
|
* <a name="ui"></a><a href="#ui">`ui`</a> - Equivalent to the [`-ui`](#_ui)
|
||||||
|
command-line flag.
|
||||||
|
|
||||||
* <a name="ui_dir"></a><a href="#ui_dir">`ui_dir`</a> - Equivalent to the
|
* <a name="ui_dir"></a><a href="#ui_dir">`ui_dir`</a> - Equivalent to the
|
||||||
[`-ui-dir`](#_ui_dir) command-line flag.
|
[`-ui-dir`](#_ui_dir) command-line flag.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue