diff --git a/Makefile b/Makefile index a07082ac5..1f8505119 100644 --- a/Makefile +++ b/Makefile @@ -157,6 +157,24 @@ storagenode-console: /usr/bin/env echo -e '\nfunc init() { FileSystem = AssetFile() }' >> storagenode/console/consoleassets/bindata.resource.go gofmt -w -s storagenode/console/consoleassets/bindata.resource.go +.PHONY: multinode-console +multinode-console: + # build web assets + rm -rf web/multinode/dist + # install npm dependencies and build the binaries + docker run --rm -i \ + --mount type=bind,src="${PWD}",dst=/go/src/storj.io/storj \ + -w /go/src/storj.io/storj/web/multinode \ + -e HOME=/tmp \ + -u $(shell id -u):$(shell id -g) \ + node:14.15.3 \ + /bin/bash -c "npm ci && npm run build" + # embed web assets into go + go-bindata -prefix web/multinode/ -fs -o multinode/console/consoleassets/bindata.resource.go -pkg consoleassets web/multinode/dist/... web/multinode/static/... + # configure existing go code to know about the new assets + /usr/bin/env echo -e '\nfunc init() { FileSystem = AssetFile() }' >> multinode/console/consoleassets/bindata.resource.go + gofmt -w -s multinode/console/consoleassets/bindata.resource.go + .PHONY: satellite-wasm satellite-wasm: docker run --rm -i -v "${PWD}":/go/src/storj.io/storj -e GO111MODULE=on \ @@ -283,13 +301,16 @@ uplink_%: .PHONY: versioncontrol_% versioncontrol_%: $(MAKE) binary-check COMPONENT=versioncontrol GOARCH=$(word 3, $(subst _, ,$@)) GOOS=$(word 2, $(subst _, ,$@)) +.PHONY: multinode_% +multinode_%: multinode-console + $(MAKE) binary-check COMPONENT=multinode GOARCH=$(word 3, $(subst _, ,$@)) GOOS=$(word 2, $(subst _, ,$@)) -COMPONENTLIST := certificates identity inspector satellite storagenode storagenode-updater uplink versioncontrol +COMPONENTLIST := certificates identity inspector satellite storagenode storagenode-updater uplink versioncontrol multinode OSARCHLIST := darwin_amd64 linux_amd64 linux_arm linux_arm64 windows_amd64 freebsd_amd64 BINARIES := $(foreach C,$(COMPONENTLIST),$(foreach O,$(OSARCHLIST),$C_$O)) .PHONY: binaries -binaries: ${BINARIES} ## Build certificates, identity, inspector, satellite, storagenode, uplink, and versioncontrol binaries (jenkins) +binaries: ${BINARIES} ## Build certificates, identity, inspector, satellite, storagenode, uplink, versioncontrol and multinode binaries (jenkins) .PHONY: sign-windows-installer sign-windows-installer: diff --git a/multinode/console/consoleassets/assets.go b/multinode/console/consoleassets/assets.go new file mode 100644 index 000000000..db6fd5da9 --- /dev/null +++ b/multinode/console/consoleassets/assets.go @@ -0,0 +1,13 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package consoleassets + +import ( + "net/http" +) + +// FileSystem is nil by default, but when our Makefile generates +// embedded resources via go-bindata, it will also drop an init method +// that sets this to not nil. +var FileSystem http.FileSystem diff --git a/multinode/console/server/server.go b/multinode/console/server/server.go index 3e1c19c5c..bdcfdf0b6 100644 --- a/multinode/console/server/server.go +++ b/multinode/console/server/server.go @@ -6,9 +6,9 @@ package server import ( "context" "html/template" + "io/ioutil" "net" "net/http" - "path/filepath" "github.com/gorilla/mux" "github.com/zeebo/errs" @@ -52,7 +52,7 @@ type Server struct { log *zap.Logger listener net.Listener http http.Server - config Config + assets http.FileSystem nodes *nodes.Service payouts *payouts.Service @@ -65,11 +65,11 @@ type Server struct { } // NewServer returns new instance of Multinode Dashboard http server. -func NewServer(log *zap.Logger, listener net.Listener, config Config, services Services) (*Server, error) { +func NewServer(log *zap.Logger, listener net.Listener, assets http.FileSystem, services Services) (*Server, error) { server := Server{ log: log, listener: listener, - config: config, + assets: assets, nodes: services.Nodes, operators: services.Operators, payouts: services.Payouts, @@ -79,7 +79,6 @@ func NewServer(log *zap.Logger, listener net.Listener, config Config, services S } router := mux.NewRouter() - fs := http.FileServer(http.Dir(server.config.StaticDir)) apiRouter := router.PathPrefix("/api/v0").Subrouter() apiRouter.NotFoundHandler = controllers.NewNotFound(server.log) @@ -133,7 +132,8 @@ func NewServer(log *zap.Logger, listener net.Listener, config Config, services S reputationRouter := apiRouter.PathPrefix("/reputation").Subrouter() reputationRouter.HandleFunc("/satellites/{satelliteID}", reputationController.Stats) - if server.config.StaticDir != "" { + if server.assets != nil { + fs := http.FileServer(server.assets) router.PathPrefix("/static/").Handler(http.StripPrefix("/static", fs)) router.PathPrefix("/").HandlerFunc(server.appHandler) } @@ -193,9 +193,19 @@ func (server *Server) Close() error { // initializeTemplates is used to initialize all templates. func (server *Server) initializeTemplates() (err error) { - server.index, err = template.ParseFiles(filepath.Join(server.config.StaticDir, "dist", "index.html")) + f, err := server.assets.Open("/dist/index.html") if err != nil { server.log.Error("dist folder is not generated. use 'npm run build' command", zap.Error(err)) + return nil + } + b, err := ioutil.ReadAll(f) + if err != nil { + return Error.Wrap(err) + } + + server.index, err = template.New("index.html").Parse(string(b)) + if err != nil { + return Error.Wrap(err) } return nil diff --git a/multinode/peer.go b/multinode/peer.go index ea1e39229..f97153514 100644 --- a/multinode/peer.go +++ b/multinode/peer.go @@ -6,6 +6,7 @@ package multinode import ( "context" "net" + "net/http" "github.com/spacemonkeygo/monkit/v3" "go.uber.org/zap" @@ -16,6 +17,7 @@ import ( "storj.io/common/rpc" "storj.io/private/debug" "storj.io/storj/multinode/bandwidth" + "storj.io/storj/multinode/console/consoleassets" "storj.io/storj/multinode/console/server" "storj.io/storj/multinode/nodes" "storj.io/storj/multinode/operators" @@ -173,10 +175,16 @@ func New(log *zap.Logger, full *identity.FullIdentity, config Config, db DB) (_ return nil, err } + assets := consoleassets.FileSystem + if config.Console.StaticDir != "" { + // a specific directory has been configured. use it + assets = http.Dir(config.Console.StaticDir) + } + peer.Console.Endpoint, err = server.NewServer( peer.Log.Named("console:endpoint"), peer.Console.Listener, - config.Console, + assets, server.Services{ Nodes: peer.Nodes.Service, Payouts: peer.Payouts.Service,