Merge pull request #1543 from hashicorp/f-ui-static

Static asset compilation for Consul UI
This commit is contained in:
Ryan Uber 2015-12-24 23:04:00 -05:00
commit b3a829589b
10 changed files with 521 additions and 11 deletions

View File

@ -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

View File

@ -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

View File

@ -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
} }

View File

@ -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,

View File

@ -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

View File

@ -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")

View File

@ -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()

View File

@ -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.

View File

@ -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.