1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

ui: Display server configuration on status page

This commit is contained in:
James Hillyerd
2018-11-26 22:19:37 -08:00
parent 7a16f64ff0
commit 9b3049562d
7 changed files with 326 additions and 50 deletions

View File

@@ -3,13 +3,19 @@
# description: Developer friendly Inbucket configuration
export INBUCKET_LOGLEVEL="debug"
export INBUCKET_SMTP_REJECTDOMAINS="bad-actors.local"
#export INBUCKET_SMTP_DEFAULTACCEPT="false"
export INBUCKET_SMTP_ACCEPTDOMAINS="good-actors.local"
export INBUCKET_SMTP_DISCARDDOMAINS="bitbucket.local"
#export INBUCKET_SMTP_DEFAULTSTORE="false"
export INBUCKET_SMTP_STOREDOMAINS="important.local"
export INBUCKET_WEB_TEMPLATECACHE="false"
export INBUCKET_WEB_COOKIEAUTHKEY="not-secret"
export INBUCKET_WEB_UIDIR="ui/dist"
export INBUCKET_STORAGE_TYPE="file"
export INBUCKET_STORAGE_PARAMS="path:/tmp/inbucket"
export INBUCKET_STORAGE_RETENTIONPERIOD="3h"
export INBUCKET_STORAGE_MAILBOXMSGCAP="300"
if ! test -x ./inbucket; then
echo "$PWD/inbucket not found/executable!" >&2

View File

@@ -71,21 +71,31 @@ func RootMonitorMailbox(w http.ResponseWriter, req *http.Request, ctx *web.Conte
// RootStatus serves the Inbucket status page
func RootStatus(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
// Get flash messages, save session
errorFlash := ctx.Session.Flashes("errors")
if err = ctx.Session.Save(req, w); err != nil {
return err
root := ctx.RootConfig
retPeriod := ""
if root.Storage.RetentionPeriod > 0 {
retPeriod = root.Storage.RetentionPeriod.String()
}
// Render template
return web.RenderTemplate("root/status.html", w, map[string]interface{}{
"ctx": ctx,
"errorFlash": errorFlash,
"version": config.Version,
"buildDate": config.BuildDate,
"smtpListener": ctx.RootConfig.SMTP.Addr,
"pop3Listener": ctx.RootConfig.POP3.Addr,
"webListener": ctx.RootConfig.Web.Addr,
"smtpConfig": ctx.RootConfig.SMTP,
"storageConfig": ctx.RootConfig.Storage,
return web.RenderJSON(w,
&jsonServerConfig{
Version: config.Version,
BuildDate: config.BuildDate,
POP3Listener: root.POP3.Addr,
WebListener: root.Web.Addr,
SMTPConfig: jsonSMTPConfig{
Addr: root.SMTP.Addr,
DefaultAccept: root.SMTP.DefaultAccept,
AcceptDomains: root.SMTP.AcceptDomains,
RejectDomains: root.SMTP.RejectDomains,
DefaultStore: root.SMTP.DefaultStore,
StoreDomains: root.SMTP.StoreDomains,
DiscardDomains: root.SMTP.DiscardDomains,
},
StorageConfig: jsonStorageConfig{
MailboxMsgCap: root.Storage.MailboxMsgCap,
StoreType: root.Storage.Type,
RetentionPeriod: retPeriod,
},
})
}

26
pkg/webui/status_json.go Normal file
View File

@@ -0,0 +1,26 @@
package webui
type jsonServerConfig struct {
Version string `json:"version"`
BuildDate string `json:"build-date"`
POP3Listener string `json:"pop3-listener"`
WebListener string `json:"web-listener"`
SMTPConfig jsonSMTPConfig `json:"smtp-config"`
StorageConfig jsonStorageConfig `json:"storage-config"`
}
type jsonSMTPConfig struct {
Addr string `json:"addr"`
DefaultAccept bool `json:"default-accept"`
AcceptDomains []string `json:"accept-domains"`
RejectDomains []string `json:"reject-domains"`
DefaultStore bool `json:"default-store"`
StoreDomains []string `json:"store-domains"`
DiscardDomains []string `json:"discard-domains"`
}
type jsonStorageConfig struct {
MailboxMsgCap int `json:"mailbox-msg-cap"`
StoreType string `json:"store-type"`
RetentionPeriod string `json:"retention-period"`
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,107 @@
module Data.ServerConfig exposing (ServerConfig, decoder, encode)
import Json.Decode as D
import Json.Decode.Pipeline as P
import Json.Encode as E
-- Generated by https://github.com/jhillyerd/go-to-elm-json
type alias ServerConfig =
{ version : String
, buildDate : String
, pop3Listener : String
, webListener : String
, smtpConfig : SmtpConfig
, storageConfig : StorageConfig
}
type alias SmtpConfig =
{ addr : String
, defaultAccept : Bool
, acceptDomains : Maybe (List String)
, rejectDomains : Maybe (List String)
, defaultStore : Bool
, storeDomains : Maybe (List String)
, discardDomains : Maybe (List String)
}
type alias StorageConfig =
{ mailboxMsgCap : Int
, storeType : String
, retentionPeriod : String
}
decoder : D.Decoder ServerConfig
decoder =
D.succeed ServerConfig
|> P.required "version" D.string
|> P.required "build-date" D.string
|> P.required "pop3-listener" D.string
|> P.required "web-listener" D.string
|> P.required "smtp-config" smtpConfigDecoder
|> P.required "storage-config" storageConfigDecoder
encode : ServerConfig -> E.Value
encode r =
E.object
[ ( "version", E.string r.version )
, ( "build-date", E.string r.buildDate )
, ( "pop3-listener", E.string r.pop3Listener )
, ( "web-listener", E.string r.webListener )
, ( "smtp-config", encodeSmtpConfig r.smtpConfig )
, ( "storage-config", encodeStorageConfig r.storageConfig )
]
smtpConfigDecoder : D.Decoder SmtpConfig
smtpConfigDecoder =
D.succeed SmtpConfig
|> P.required "addr" D.string
|> P.required "default-accept" D.bool
|> P.required "accept-domains" (D.nullable (D.list D.string))
|> P.required "reject-domains" (D.nullable (D.list D.string))
|> P.required "default-store" D.bool
|> P.required "store-domains" (D.nullable (D.list D.string))
|> P.required "discard-domains" (D.nullable (D.list D.string))
encodeSmtpConfig : SmtpConfig -> E.Value
encodeSmtpConfig r =
E.object
[ ( "addr", E.string r.addr )
, ( "default-accept", E.bool r.defaultAccept )
, ( "accept-domains", maybe (E.list E.string) r.acceptDomains )
, ( "reject-domains", maybe (E.list E.string) r.rejectDomains )
, ( "default-store", E.bool r.defaultStore )
, ( "store-domains", maybe (E.list E.string) r.storeDomains )
, ( "discard-domains", maybe (E.list E.string) r.discardDomains )
]
storageConfigDecoder : D.Decoder StorageConfig
storageConfigDecoder =
D.succeed StorageConfig
|> P.required "mailbox-msg-cap" D.int
|> P.required "store-type" D.string
|> P.required "retention-period" D.string
encodeStorageConfig : StorageConfig -> E.Value
encodeStorageConfig r =
E.object
[ ( "mailbox-msg-cap", E.int r.mailboxMsgCap )
, ( "store-type", E.string r.storeType )
, ( "retention-period", E.string r.retentionPeriod )
]
maybe : (a -> E.Value) -> Maybe a -> E.Value
maybe encoder =
Maybe.map encoder >> Maybe.withDefault E.null

View File

@@ -1,6 +1,7 @@
module Page.Status exposing (Model, Msg, init, subscriptions, update, view)
import Data.Metrics as Metrics exposing (Metrics)
import Data.ServerConfig as ServerConfig exposing (ServerConfig)
import Data.Session as Session exposing (Session)
import Filesize
import Html exposing (..)
@@ -17,7 +18,8 @@ import Time exposing (Posix)
type alias Model =
{ metrics : Maybe Metrics
{ config : Maybe ServerConfig
, metrics : Maybe Metrics
, xCounter : Float
, sysMem : Metric
, heapSize : Metric
@@ -48,7 +50,8 @@ type alias Metric =
init : ( Model, Cmd Msg, Session.Msg )
init =
( { metrics = Nothing
( { config = Nothing
, metrics = Nothing
, xCounter = 60
, sysMem = Metric "System Memory" 0 Filesize.format graphZero initDataSet 10
, heapSize = Metric "Heap Size" 0 Filesize.format graphZero initDataSet 10
@@ -65,7 +68,7 @@ init =
, retainedCount = Metric "Stored Messages" 0 fmtInt graphZero initDataSet 60
, retainedSize = Metric "Store Size" 0 Filesize.format graphZero initDataSet 60
}
, getMetrics
, Cmd.batch [ loadServerConfig, loadMetrics ]
, Session.none
)
@@ -91,6 +94,7 @@ subscriptions model =
type Msg
= MetricsReceived (Result Http.Error Metrics)
| ServerConfigLoaded (Result Http.Error ServerConfig)
| Tick Posix
@@ -103,8 +107,14 @@ update session msg model =
MetricsReceived (Err err) ->
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
ServerConfigLoaded (Ok config) ->
( { model | config = Just config }, Cmd.none, Session.none )
ServerConfigLoaded (Err err) ->
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
Tick time ->
( model, getMetrics, Session.ClearFlash )
( model, loadMetrics, Session.none )
{-| Update all metrics in Model; increment xCounter.
@@ -203,14 +213,22 @@ updateRemoteTotal metric value history =
}
getMetrics : Cmd Msg
getMetrics =
loadMetrics : Cmd Msg
loadMetrics =
Http.get
{ url = "/debug/vars"
, expect = Http.expectJson MetricsReceived Metrics.decoder
}
loadServerConfig : Cmd Msg
loadServerConfig =
Http.get
{ url = "/serve/status"
, expect = Http.expectJson ServerConfigLoaded ServerConfig.decoder
}
-- VIEW --
@@ -221,12 +239,111 @@ view session model =
, content =
div [ class "page" ]
[ h1 [] [ text "Status" ]
, case model.metrics of
Nothing ->
div [] [ text "Loading metrics..." ]
, div [] (configPanel model.config :: metricPanels model)
]
}
Just metrics ->
div []
configPanel : Maybe ServerConfig -> Html Msg
configPanel maybeConfig =
let
mailboxCap config =
case config.storageConfig.mailboxMsgCap of
0 ->
"Unlimited"
cap ->
String.fromInt cap ++ " messages per mailbox"
retentionPeriod config =
case config.storageConfig.retentionPeriod of
"" ->
"Forever"
period ->
period
in
case maybeConfig of
Nothing ->
text "Loading server config..."
Just config ->
framePanel "Configuration"
[ textEntry "Version" (config.version ++ ", built on " ++ config.buildDate)
, textEntry "SMTP Listener" config.smtpConfig.addr
, textEntry "POP3 Listener" config.pop3Listener
, textEntry "HTTP Listener" config.webListener
, textEntry "Accept Policy" (acceptPolicy config.smtpConfig)
, textEntry "Store Policy" (storePolicy config.smtpConfig)
, textEntry "Store Type" config.storageConfig.storeType
, textEntry "Message Cap" (mailboxCap config)
, textEntry "Retention Period" (retentionPeriod config)
]
acceptPolicy config =
if config.defaultAccept then
"All domains"
++ (case config.rejectDomains of
Nothing ->
""
Just [] ->
""
Just domains ->
", except: " ++ String.join ", " domains
)
else
"No domains"
++ (case config.acceptDomains of
Nothing ->
""
Just [] ->
""
Just domains ->
", except: " ++ String.join ", " domains
)
storePolicy config =
if config.defaultStore then
"All domains"
++ (case config.discardDomains of
Nothing ->
""
Just [] ->
""
Just domains ->
", except: " ++ String.join ", " domains
)
else
"No domains"
++ (case config.storeDomains of
Nothing ->
""
Just [] ->
""
Just domains ->
", except: " ++ String.join ", " domains
)
metricPanels : Model -> List (Html Msg)
metricPanels model =
case model.metrics of
Nothing ->
[ text "Loading metrics..." ]
Just _ ->
[ framePanel "General Metrics"
[ viewMetric model.sysMem
, viewMetric model.heapSize
@@ -248,8 +365,14 @@ view session model =
, viewMetric model.retainedSize
]
]
textEntry : String -> String -> Html Msg
textEntry name value =
div [ class "metric" ]
[ div [ class "label" ] [ text name ]
, div [ class "text-value" ] [ text value ]
]
}
viewMetric : Metric -> Html Msg

View File

@@ -462,6 +462,10 @@ nav.tab-bar a.active:hover {
flex-basis: 15em;
}
.metric .text-value {
flex-basis: 40em;
}
.metric .graph {
flex-basis: 25em;
}