Code

Add support for variable root mount points.
authorSebastian Harl <sh@tokkee.org>
Sun, 24 Jan 2016 19:14:03 +0000 (20:14 +0100)
committerSebastian Harl <sh@tokkee.org>
Sun, 24 Jan 2016 19:14:03 +0000 (20:14 +0100)
That is, make it possible to serve the webUI from a different path than /.

main.go
server/error.go
server/server.go
templates/graphs.tmpl
templates/host.tmpl
templates/hosts.tmpl
templates/main.tmpl
templates/metric.tmpl
templates/metrics.tmpl
templates/service.tmpl
templates/services.tmpl

diff --git a/main.go b/main.go
index 5ded81417cedb53920b393cbaacd471d64ee9e9b..699651c744ee7890c64f80bec32d296edc3e9e00 100644 (file)
--- a/main.go
+++ b/main.go
@@ -44,6 +44,8 @@ var (
        listen = flag.String("listen", ":8080", "address to listen for incoming connections")
        tmpl   = flag.String("template-path", "templates", "location of template files")
        static = flag.String("static-path", "static", "location of static files")
+
+       root = flag.String("root", "/", "root mount point of the server")
 )
 
 func init() {
@@ -65,13 +67,14 @@ func main() {
        srv, err := server.New(*addr, *username, server.Config{
                TemplatePath: *tmpl,
                StaticPath:   *static,
+               Root:         *root,
        })
        if err != nil {
                fatalf("Failed to construct web-server: %v", err)
        }
 
        log.Printf("Listening on %s.", *listen)
-       http.Handle("/", srv)
+       http.Handle(*root, srv)
        err = http.ListenAndServe(*listen, nil)
        if err != nil {
                fatalf("Failed to set up HTTP server on address %q: %v", *listen, err)
index 270225a32473392bb4c1a932423a4c3ade058c6c..8509b3d3f131b78084ae38f9f22ee485f10e5fd8 100644 (file)
@@ -36,7 +36,7 @@ import (
 )
 
 func (s *Server) notfound(w http.ResponseWriter, r *http.Request) {
-       s.err(w, http.StatusNotFound, fmt.Errorf("%s not found", r.RequestURI))
+       s.err(w, http.StatusNotFound, fmt.Errorf("%s not found", r.URL.Path))
 }
 
 func (s *Server) badrequest(w http.ResponseWriter, err error) {
index 1f5ea94a3879f8a26ddb98a27455393e5eeebca6..fb5ba225a194dc3f5c94cebe6010994047961ae4 100644 (file)
@@ -47,6 +47,9 @@ type Config struct {
 
        // StaticPath specifies the relative or absolute location of static files.
        StaticPath string
+
+       // Root mount point of the server.
+       Root string
 }
 
 // A Server implements an http.Handler that serves the SysDB user interface.
@@ -62,11 +65,21 @@ type Server struct {
 
        // Base directory of static files.
        basedir string
+
+       // Root mount point.
+       root string
 }
 
 // New constructs a new SysDB web server using the specified configuration.
 func New(addr, user string, cfg Config) (*Server, error) {
-       s := &Server{results: make(map[string]*template.Template)}
+       s := &Server{
+               results: make(map[string]*template.Template),
+               basedir: cfg.StaticPath,
+               root:    cfg.Root,
+       }
+       if s.root == "" {
+               s.root = "/"
+       }
 
        var err error
        if s.c, err = client.Connect(addr, user); err != nil {
@@ -76,18 +89,17 @@ func New(addr, user string, cfg Config) (*Server, error) {
                log.Printf("Connected to SysDB %d.%d.%d%s.", major, minor, patch, extra)
        }
 
-       if s.main, err = cfg.parse("main.tmpl"); err != nil {
+       if s.main, err = cfg.parse(s, "main.tmpl"); err != nil {
                return nil, err
        }
        types := []string{"graphs", "host", "hosts", "service", "services", "metric", "metrics"}
        for _, t := range types {
-               s.results[t], err = cfg.parse(t + ".tmpl")
+               s.results[t], err = cfg.parse(s, t+".tmpl")
                if err != nil {
                        return nil, err
                }
        }
 
-       s.basedir = cfg.StaticPath
        s.mux = map[string]handler{
                "images": s.static,
                "style":  s.static,
@@ -96,8 +108,10 @@ func New(addr, user string, cfg Config) (*Server, error) {
        return s, nil
 }
 
-func (cfg Config) parse(name string) (*template.Template, error) {
-       t := template.New(filepath.Base(name))
+func (cfg Config) parse(s *Server, name string) (*template.Template, error) {
+       t := template.New(filepath.Base(name)).Funcs(template.FuncMap{
+               "root": s.Root,
+       })
        return t.ParseFiles(filepath.Join(cfg.TemplatePath, name))
 }
 
@@ -134,6 +148,13 @@ var content = map[string]func(request, *Server) (*page, error){
 // the SysDB user interface.
 func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        path := r.RequestURI
+       if !strings.HasPrefix(path, s.root) {
+               s.notfound(w, r)
+               return
+       }
+       path = strings.TrimPrefix(path, s.root)
+       r.URL.Path = strings.TrimPrefix(r.URL.Path, s.root)
+
        if len(path) > 0 && path[0] == '/' {
                path = path[1:]
        }
@@ -205,6 +226,15 @@ func (s *Server) static(w http.ResponseWriter, req request) {
        http.ServeFile(w, req.r, filepath.Clean(filepath.Join(s.basedir, req.r.URL.Path)))
 }
 
+// Root returns the root mount point of the server suitable for use as a path
+// prefix.
+func (s *Server) Root() string {
+       if s.root[len(s.root)-1] == '/' {
+               return s.root
+       }
+       return s.root + "/"
+}
+
 func index(_ request, s *Server) (*page, error) {
        major, minor, patch, extra, err := s.c.ServerVersion()
        if err != nil {
index 5c8b4907904f0740b123334db7ad398229c3e839..221273a5be58aa2c1dc71bc896044d0acedffa58 100644 (file)
@@ -1,6 +1,6 @@
 <section>
        <h1>Graphs</h1>
-       <form action="/graphs" method="POST">
+       <form action="{{root}}graphs" method="POST">
                <p><input type="text" name="metrics-query" value="{{.Query}}"
                       class="query" placeholder="Search metrics" required />
                <button type="submit">GO</button></p>
@@ -13,7 +13,7 @@
 {{end}}
        </form><br />
 {{if .Metrics}}
-       <img src="/graph/q{{urlquery .QueryOptions}}/{{urlquery .Metrics}}" border="0" />
+       <img src="{{root}}graph/q{{urlquery .QueryOptions}}/{{urlquery .Metrics}}" border="0" />
 {{end}}
        <p>&nbsp;</p>
 </section>
index 6193070e06be7acc2043a63304553f5025f2c93a..4f1ea1fddf46be28d17e59aea2302435b8c3d93e 100644 (file)
@@ -15,7 +15,7 @@
 {{if len .Services}}
                <tr><th colspan="2">Services</th></tr>
        {{range .Services}}
-               <tr><td colspan="2"><a href="/service/{{urlquery $.Name}}/{{urlquery .Name}}">{{.Name}}</a></td></tr>
+               <tr><td colspan="2"><a href="{{root}}service/{{urlquery $.Name}}/{{urlquery .Name}}">{{.Name}}</a></td></tr>
        {{end}}
 {{else}}
                <tr><th colspan="2">No services</th></tr>
@@ -23,7 +23,7 @@
 {{if len .Metrics}}
                <tr><th colspan="2">Metrics</th></tr>
        {{range .Metrics}}
-               <tr><td colspan="2"><a href="/metric/{{urlquery $.Name}}/{{urlquery .Name}}">{{.Name}}</a></td></tr>
+               <tr><td colspan="2"><a href="{{root}}metric/{{urlquery $.Name}}/{{urlquery .Name}}">{{.Name}}</a></td></tr>
        {{end}}
 {{else}}
                <tr><th colspan="2">No Metrics</th></tr>
index 4eabaef2e7d71dded601f296ddb1e652d5b2945f..aff7aa882c30dd24e331ddb594f2b2bb88542cd8 100644 (file)
@@ -4,7 +4,7 @@
        <table class="results">
                <tr><th>Host</th><th>Last update</th></tr>
        {{range .}}
-               <tr><td><a href="/host/{{urlquery .Name}}">{{.Name}}</a></td><td>{{.LastUpdate}}</td></tr>
+               <tr><td><a href="{{root}}host/{{urlquery .Name}}">{{.Name}}</a></td><td>{{.LastUpdate}}</td></tr>
        {{end}}
        </table>
 {{else}}
index e6049ebd41bc31b6cf04c049886b4b4db6daeba9..46575f586ce0872e73e289550eb544469b0cf387 100644 (file)
@@ -10,8 +10,8 @@
 
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
-       <link rel="stylesheet" href="/style/main.css" type="text/css" />
-       <link rel="icon" href="/images/favicon.png" type="images/png" />
+       <link rel="stylesheet" href="{{root}}style/main.css" type="text/css" />
+       <link rel="icon" href="{{root}}images/favicon.png" type="images/png" />
 </head>
 
 <body>
                </div>
                <div class="searchbar">
                        <div class="logo">
-                               <a href="/"><img src="/images/owl.png" alt="[SysDB]" class="logo" /></a>
+                               <a href="{{root}}"><img src="{{root}}images/owl.png" alt="[SysDB]" class="logo" /></a>
                        </div>
 
                        <div class="searchbox">
-                               <form action="/lookup" method="POST">
+                               <form action="{{root}}lookup" method="POST">
                                        <input type="text" name="query" value="{{.Query}}" placeholder="Search objects"
                                                required /><button type="submit">GO</button>
                                </form>
 
        <div class="main">
                <aside><nav>
-                       <a href="/hosts">Hosts</a>
-                       <a href="/services">Services</a>
-                       <a href="/metrics">Metrics</a>
-                       <a href="/graphs">Graphs</a>
+                       <a href="{{root}}hosts">Hosts</a>
+                       <a href="{{root}}services">Services</a>
+                       <a href="{{root}}metrics">Metrics</a>
+                       <a href="{{root}}graphs">Graphs</a>
                </nav></aside>
 
                <div class="content">
index 5dc51c1008a0e2ad113bbbb3127a7dfa4e91bd71..24b5991a27523d92ced296a7e21a8f5eecc55100 100644 (file)
@@ -1,17 +1,17 @@
 <section>{{$m := index .Data.Metrics 0}}
        <h1>Metric {{.Data.Name}} &mdash; {{$m.Name}}</h1>
 {{if $m.Timeseries}}
-       <form action="/metric/{{urlquery .Data.Name}}/{{urlquery $m.Name}}" method="POST">
+       <form action="{{root}}metric/{{urlquery .Data.Name}}/{{urlquery $m.Name}}" method="POST">
                <b>Time range:</b>
                <input type="text" name="start_date" value="{{.StartTime}}" class="datetime">
                &mdash;
                <input type="text" name="end_date" value="{{.EndTime}}" class="datetime">
                <button type="submit">Apply</button>
        </form><br />
-       <img src="/graph/{{urlquery .Data.Name}}/{{urlquery $m.Name}}/{{.URLStart}}/{{.URLEnd}}" border="0" />
+       <img src="{{root}}graph/{{urlquery .Data.Name}}/{{urlquery $m.Name}}/{{.URLStart}}/{{.URLEnd}}" border="0" />
 {{end}}
        <table class="results">
-               <tr><td><b>Host</b></td><td><a href="/host/{{urlquery .Data.Name}}">{{.Data.Name}}</a></td></tr>
+               <tr><td><b>Host</b></td><td><a href="{{root}}host/{{urlquery .Data.Name}}">{{.Data.Name}}</a></td></tr>
                <tr><td><b>Last update</b></td><td>{{$m.LastUpdate}}</td></tr>
                <tr><td><b>Update interval</b></td><td>{{$m.UpdateInterval}}</td></tr>
                <tr><td><b>Backends</b></td><td>{{$m.Backends}}</td></tr>
index 88fe308174ea043cee85b05f371b34ff26ea9ffb..5c1e489fd919f18d8d0bb92512498ad95320cb1c 100644 (file)
@@ -6,9 +6,9 @@
        {{range $h := .}}
                {{range $i, $m := $h.Metrics}}
                {{if not $i}}
-               <tr><td rowspan="{{len $h.Metrics}}"><a href="/host/{{urlquery $h.Name}}">{{$h.Name}}</a></td><td><a href="/metric/{{urlquery $h.Name}}/{{urlquery $m.Name}}">{{$m.Name}}</a></td><td>{{$m.LastUpdate}}</td>
+               <tr><td rowspan="{{len $h.Metrics}}"><a href="{{root}}host/{{urlquery $h.Name}}">{{$h.Name}}</a></td><td><a href="{{root}}metric/{{urlquery $h.Name}}/{{urlquery $m.Name}}">{{$m.Name}}</a></td><td>{{$m.LastUpdate}}</td>
                {{else}}
-               <tr><td><a href="/metric/{{urlquery $h.Name}}/{{urlquery $m.Name}}">{{$m.Name}}</a></td><td>{{$m.LastUpdate}}</td></tr>
+               <tr><td><a href="{{root}}metric/{{urlquery $h.Name}}/{{urlquery $m.Name}}">{{$m.Name}}</a></td><td>{{$m.LastUpdate}}</td></tr>
        {{end}}{{end}}{{end}}
        </table>
 {{else}}
index a232458b326ff125d084398a2c3511ca680ac452..4a1fcb6fd583d56a07f54237d878f4f9c923c56f 100644 (file)
@@ -1,7 +1,7 @@
 <section>{{$s := index .Services 0}}
        <h1>Service {{$.Name}} &mdash; {{$s.Name}}</h1>
        <table class="results">
-               <tr><td><b>Host</b></td><td><a href="/host/{{urlquery $.Name}}">{{$.Name}}</a></td></tr>
+               <tr><td><b>Host</b></td><td><a href="{{root}}host/{{urlquery $.Name}}">{{$.Name}}</a></td></tr>
                <tr><td><b>Last update</b></td><td>{{$s.LastUpdate}}</td></tr>
                <tr><td><b>Update interval</b></td><td>{{$s.UpdateInterval}}</td></tr>
                <tr><td><b>Backends</b></td><td>{{$s.Backends}}</td></tr>
index 151d239921bc8be215c6ed52fa4301ceaec63495..7e7e843b7ac39d2082b5f96c595f033657614219 100644 (file)
@@ -6,9 +6,9 @@
        {{range $h := .}}
                {{range $i, $s := $h.Services}}
                {{if not $i}}
-               <tr><td rowspan="{{len $h.Services}}"><a href="/host/{{urlquery $h.Name}}">{{$h.Name}}</a></td><td><a href="/service/{{urlquery $h.Name}}/{{urlquery $s.Name}}">{{$s.Name}}</a></td><td>{{$s.LastUpdate}}</td>
+               <tr><td rowspan="{{len $h.Services}}"><a href="{{root}}host/{{urlquery $h.Name}}">{{$h.Name}}</a></td><td><a href="{{root}}service/{{urlquery $h.Name}}/{{urlquery $s.Name}}">{{$s.Name}}</a></td><td>{{$s.LastUpdate}}</td>
                {{else}}
-               <tr><td><a href="/service/{{urlquery $h.Name}}/{{urlquery $s.Name}}">{{$s.Name}}</a></td><td>{{$s.LastUpdate}}</td></tr>
+               <tr><td><a href="{{root}}service/{{urlquery $h.Name}}/{{urlquery $s.Name}}">{{$s.Name}}</a></td><td>{{$s.LastUpdate}}</td></tr>
        {{end}}{{end}}{{end}}
        </table>
 {{else}}