mirror of
https://github.com/sablierapp/sablier.git
synced 2026-01-04 20:14:58 +01:00
feat: add custom loading page (#15)
* add option for custom loading and error pages * document custom landing pages * link to example templates * update loading page template to match template actually in-use
This commit is contained in:
18
README.md
18
README.md
@@ -23,18 +23,26 @@ Traefik middleware to start containers on demand.
|
||||
|
||||
### Plugin configuration
|
||||
|
||||
**Custom loading/error pages**
|
||||
The `loadingpage` and `errorpage` keys in the plugin configuration can be used to override the default loading and error pages. The value should be a path where a template that can be parsed by Go's [html/template](https://pkg.go.dev/html/template) package can be found in the Traefik container. An example of both a loading page and an error page template can be found in the [pkg/pages/](pkg/pages/) directory in [loading.html](pkg/pages/loading.html) and [error.html](pkg/pages/error.html) respectively. The plugin will default to the built-in loading and error pages if these fields are omitted.
|
||||
|
||||
**Example Configuration**
|
||||
```yml
|
||||
testData:
|
||||
serviceUrl: http://ondemand:10000
|
||||
name: TRAEFIK_HACKATHON_whoami
|
||||
timeout: 1m
|
||||
loadingpage: /opt/on-demand/loading.html
|
||||
errorpage: /opt/on-demand/error.html
|
||||
```
|
||||
|
||||
| Parameter | Type | Example | Description |
|
||||
| ------------ | --------------- | -------------------------- | ----------------------------------------------------------------------- |
|
||||
| `serviceUrl` | `string` | `http://ondemand:10000` | The docker container name, or the swarm service name |
|
||||
| `name` | `string` | `TRAEFIK_HACKATHON_whoami` | The container/service to be stopped (docker ps | docker service ls) |
|
||||
| `timeout` | `time.Duration` | `1m30s` | The duration after which the container/service will be scaled down to 0 |
|
||||
| Parameter | Type | Example | Description |
|
||||
| ------------ | --------------- | -------------------------- | ----------------------------------------------------------------------- |
|
||||
| `serviceUrl` | `string` | `http://ondemand:10000` | The docker container name, or the swarm service name |
|
||||
| `name` | `string` | `TRAEFIK_HACKATHON_whoami` | The container/service to be stopped (docker ps | docker service ls) |
|
||||
| `timeout` | `time.Duration` | `1m30s` | The duration after which the container/service will be scaled down to 0 |
|
||||
| `loadingpage`| `string` | `/opt/on-demand/loading.html` | The path in the traefik container for the loading page template |
|
||||
| `errorpage` | `string` | `/opt/on-demand/error.html` | The path in the traefik container for the error page template |
|
||||
|
||||
### Traefik-Ondemand-Service
|
||||
|
||||
|
||||
34
ondemand.go
34
ondemand.go
@@ -19,9 +19,11 @@ var netClient = &http.Client{
|
||||
|
||||
// Config the plugin configuration
|
||||
type Config struct {
|
||||
Name string `yaml:"name"`
|
||||
ServiceUrl string `yaml:"serviceurl"`
|
||||
Timeout string `yaml:"timeout"`
|
||||
Name string `yaml:"name"`
|
||||
ServiceUrl string `yaml:"serviceurl"`
|
||||
Timeout string `yaml:"timeout"`
|
||||
ErrorPage string `yaml:"errorpage"`
|
||||
LoadingPage string `yaml:"loadingpage"`
|
||||
}
|
||||
|
||||
// CreateConfig creates a config with its default values
|
||||
@@ -33,10 +35,12 @@ func CreateConfig() *Config {
|
||||
|
||||
// Ondemand holds the request for the on demand service
|
||||
type Ondemand struct {
|
||||
request string
|
||||
name string
|
||||
next http.Handler
|
||||
timeout time.Duration
|
||||
request string
|
||||
name string
|
||||
next http.Handler
|
||||
timeout time.Duration
|
||||
errorpage string
|
||||
loadingpage string
|
||||
}
|
||||
|
||||
func buildRequest(url string, name string, timeout time.Duration) (string, error) {
|
||||
@@ -67,10 +71,12 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h
|
||||
}
|
||||
|
||||
return &Ondemand{
|
||||
next: next,
|
||||
name: config.Name,
|
||||
request: request,
|
||||
timeout: timeout,
|
||||
next: next,
|
||||
name: config.Name,
|
||||
request: request,
|
||||
timeout: timeout,
|
||||
errorpage: config.ErrorPage,
|
||||
loadingpage: config.LoadingPage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -83,7 +89,7 @@ func (e *Ondemand) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
if err != nil {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
rw.Write([]byte(pages.GetErrorPage(e.name, err.Error())))
|
||||
rw.Write([]byte(pages.GetErrorPage(e.errorpage, e.name, err.Error())))
|
||||
}
|
||||
|
||||
if status == "started" {
|
||||
@@ -93,11 +99,11 @@ func (e *Ondemand) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
} else if status == "starting" {
|
||||
// Service starting, notify client
|
||||
rw.WriteHeader(http.StatusAccepted)
|
||||
rw.Write([]byte(pages.GetLoadingPage(e.name, e.timeout)))
|
||||
rw.Write([]byte(pages.GetLoadingPage(e.loadingpage, e.name, e.timeout)))
|
||||
} else {
|
||||
// Error
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
rw.Write([]byte(pages.GetErrorPage(e.name, status)))
|
||||
rw.Write([]byte(pages.GetErrorPage(e.errorpage, e.name, status)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package pages
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"path"
|
||||
)
|
||||
|
||||
var errorPage = `<!doctype html>
|
||||
@@ -175,15 +176,26 @@ type ErrorData struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
func GetErrorPage(name string, e string) string {
|
||||
tpl, err := template.New("error").Parse(errorPage)
|
||||
func GetErrorPage(template_path string, name string, e string) string {
|
||||
var tpl *template.Template
|
||||
var err error
|
||||
if template_path != "" {
|
||||
tpl, err = template.New(path.Base(template_path)).ParseFiles(template_path)
|
||||
} else {
|
||||
tpl, err = template.New("loading").Parse(loadingPage)
|
||||
}
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
b := bytes.Buffer{}
|
||||
tpl.Execute(&b, ErrorData{
|
||||
err = tpl.Execute(&b, ErrorData{
|
||||
Name: name,
|
||||
Error: e,
|
||||
})
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package pages
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path"
|
||||
|
||||
"fmt"
|
||||
"html/template"
|
||||
@@ -251,16 +252,27 @@ type LoadingData struct {
|
||||
Timeout string
|
||||
}
|
||||
|
||||
func GetLoadingPage(name string, timeout time.Duration) string {
|
||||
tpl, err := template.New("loading").Parse(loadingPage)
|
||||
func GetLoadingPage(template_path string, name string, timeout time.Duration) string {
|
||||
var tpl *template.Template
|
||||
var err error
|
||||
if template_path != "" {
|
||||
tpl, err = template.New(path.Base(template_path)).ParseFiles(template_path)
|
||||
} else {
|
||||
tpl, err = template.New("loading").Parse(loadingPage)
|
||||
}
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
b := bytes.Buffer{}
|
||||
tpl.Execute(&b, LoadingData{
|
||||
err = tpl.Execute(&b, LoadingData{
|
||||
Name: name,
|
||||
Timeout: humanizeDuration(timeout),
|
||||
})
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<h2 class="headline" id="headline">{{name}} is loading...</h2>
|
||||
<h2 class="headline" id="headline">{{ .Name }} is loading...</h2>
|
||||
<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
|
||||
|
||||
<p class="message text" id="message">Your instance is loading, and will be
|
||||
@@ -222,7 +222,7 @@
|
||||
|
||||
|
||||
<div class="support text">
|
||||
Your instance will shutdown automatically after {{duration}} of
|
||||
Your instance will shutdown automatically after {{ .Timeout }} of
|
||||
inactivity.
|
||||
</div>
|
||||
</section>
|
||||
@@ -233,4 +233,4 @@
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user