aboutsummaryrefslogtreecommitdiff
path: root/cmd/monfront
diff options
context:
space:
mode:
authorGibheer <gibheer+git@zero-knowledge.org>2022-12-15 11:16:56 +0100
committerGibheer <gibheer+git@zero-knowledge.org>2022-12-15 11:16:56 +0100
commite29f38937cdf077a99b45c27e49f553d4dd8d0d7 (patch)
tree38509003a153a0100cb1a69a5d7a752ad2ff7616 /cmd/monfront
parent49dac92034f352698429ee1d78d4bfb070006693 (diff)
monfront - add basic interface to create some entities
Diffstat (limited to 'cmd/monfront')
-rw-r--r--cmd/monfront/create.go148
-rw-r--r--cmd/monfront/main.go1
-rw-r--r--cmd/monfront/server.go2
-rw-r--r--cmd/monfront/templates/create_index.html84
-rw-r--r--cmd/monfront/templates/header.html1
-rw-r--r--cmd/monfront/templates/rows_to_table.html19
6 files changed, 255 insertions, 0 deletions
diff --git a/cmd/monfront/create.go b/cmd/monfront/create.go
new file mode 100644
index 0000000..43805a1
--- /dev/null
+++ b/cmd/monfront/create.go
@@ -0,0 +1,148 @@
+package main
+
+import (
+ "database/sql"
+ "fmt"
+ "log"
+ "net/http"
+ "strings"
+)
+
+func showCreate(con *Context) {
+ if con.r.Method == "POST" {
+ addCreate(con)
+ return
+ }
+ if con.r.Method != "GET" {
+ con.w.WriteHeader(http.StatusMethodNotAllowed)
+ con.w.Write([]byte("method is not supported"))
+ return
+ }
+ if !con.CanEdit {
+ con.w.WriteHeader(http.StatusForbidden)
+ con.w.Write([]byte("no permission to change data"))
+ return
+ }
+ con.Content = map[string]any{}
+
+ primitives := []struct {
+ name string
+ query string
+ }{
+ {"commands", "select id, name, updated, command, message from commands order by name"},
+ {"checkers", "select id, name, description from checkers order by name"},
+ {"notifier", "select id, name, settings from notifier order by name"},
+ {"nodes", "select id, name, updated, message from nodes order by name"},
+ }
+ for _, prim := range primitives {
+ rows, err := DB.Query(prim.query)
+ defer rows.Close()
+ if err != nil {
+ log.Printf("could not get commands: %s", err)
+ con.Error = "could not get commands"
+ returnError(http.StatusInternalServerError, con, con.w)
+ return
+ }
+ result, err := rowsToResult(rows)
+ if err != nil {
+ log.Printf("could not get %s: %s", prim.name, err)
+ con.Error = "could not get " + prim.name
+ returnError(http.StatusInternalServerError, con, con.w)
+ return
+ }
+ con.Content[prim.name] = result
+ }
+
+ con.w.Header()["Content-Type"] = []string{"text/html"}
+ con.Render("create_index")
+ return
+}
+
+type (
+ sqlResult struct {
+ Columns []string
+ Rows [][]sql.NullString
+ }
+)
+
+func rowsToResult(rows *sql.Rows) (*sqlResult, error) {
+ res := &sqlResult{}
+ cols, err := rows.Columns()
+ if err != nil {
+ return res, fmt.Errorf("could not get columns: %w", err)
+ }
+ res.Columns = cols
+ res.Rows = [][]sql.NullString{}
+ colNum := len(cols)
+
+ for rows.Next() {
+ line := make([]sql.NullString, colNum)
+ lineMap := make([]any, colNum)
+ for i := 0; i < colNum; i++ {
+ lineMap[i] = &(line[i])
+ }
+ if err := rows.Scan(lineMap...); err != nil {
+ return res, fmt.Errorf("could not scan values: %w", err)
+ }
+ res.Rows = append(res.Rows, line)
+ }
+
+ return res, nil
+}
+
+func addCreate(con *Context) {
+ if !con.CanEdit {
+ con.w.WriteHeader(http.StatusForbidden)
+ con.w.Write([]byte("no permission to change data"))
+ return
+ }
+
+ if err := con.r.ParseForm(); err != nil {
+ con.w.WriteHeader(http.StatusBadRequest)
+ fmt.Fprintf(con.w, "could not parse parameters: %s", err)
+ return
+ }
+
+ con.w.Header()["Location"] = []string{"/create"}
+
+ addType := con.r.PostForm.Get("type")
+ types := map[string]struct {
+ Fields []string
+ Table string
+ }{
+ "command": {[]string{"name", "command", "message"}, "commands"},
+ "node": {[]string{"name", "message"}, "nodes"},
+ "checker": {[]string{"name", "description"}, "checkers"},
+ "notifier": {[]string{"name", "settings"}, "notifier"},
+ "check": {[]string{"name", "message", "options", "intval", "node_id", "command_id", "checker_id"}, "checks"},
+ }
+ t, found := types[addType]
+ if !found {
+ con.Error = "undefined type '" + addType + "'"
+ returnError(http.StatusBadRequest, con, con.w)
+ return
+ }
+
+ fields := make([]any, len(t.Fields))
+ vals := make([]string, len(t.Fields))
+ for i := 0; i < len(fields); i++ {
+ vals[i] = fmt.Sprintf(`$%d`, i+1)
+ fields[i] = con.r.PostForm.Get(t.Fields[i])
+ if fields[i] == "" {
+ con.Error = "field " + t.Fields[i] + " must not be empty"
+ returnError(http.StatusBadRequest, con, con.w)
+ return
+ }
+ }
+ stmt := `insert into ` + t.Table + `(` + strings.Join(t.Fields, ",") + `) values (` + strings.Join(vals, ",") + `)`
+ _, err := DB.Exec(stmt, fields...)
+ if err != nil {
+ log.Printf("could not insert new %s: %s", addType, err)
+ con.Error = "could not insert new " + addType
+ returnError(http.StatusInternalServerError, con, con.w)
+ return
+ }
+
+ con.w.WriteHeader(http.StatusSeeOther)
+ return
+}
diff --git a/cmd/monfront/main.go b/cmd/monfront/main.go
index 63c1b9a..a318e75 100644
--- a/cmd/monfront/main.go
+++ b/cmd/monfront/main.go
@@ -170,6 +170,7 @@ func main() {
s := newServer(l, db, tmpl, auth, autho)
s.Handle("/", showChecks)
+ s.Handle("/create", showCreate)
s.Handle("/check", showCheck)
s.Handle("/checks", showChecks)
s.Handle("/groups", showGroups)
diff --git a/cmd/monfront/server.go b/cmd/monfront/server.go
index 2ada1d0..8e53c64 100644
--- a/cmd/monfront/server.go
+++ b/cmd/monfront/server.go
@@ -46,6 +46,8 @@ type (
CheckDetails *checkDetails `json:"check_details,omitempty"`
Groups []group `json:"groups,omitempty"`
Unhandled bool `json:"-"` // set this flag when unhandled was called
+
+ Content map[string]any `json:"-"` // used for the configuration dashboard
}
)
diff --git a/cmd/monfront/templates/create_index.html b/cmd/monfront/templates/create_index.html
new file mode 100644
index 0000000..1e4a67e
--- /dev/null
+++ b/cmd/monfront/templates/create_index.html
@@ -0,0 +1,84 @@
+{{ template "header" . }}
+<section id="content">
+ <h1>create entries</h1>
+ <details>
+ <summary>checks</summary>
+ <form action="/create" method="POST">
+ <p><label>name</label><input name="name" /></p>
+ <p><label>node</label>
+ <select name="node_id">
+ {{ range $node := .Content.nodes.Rows }}
+ <option value="{{ (index . 0).String }}">{{ (index . 1).String }}</option>
+ {{ end }}
+ </select>
+ </p>
+ <p><label>command</label><select name="command_id">
+ {{ range $node := .Content.commands.Rows }}
+ <option value="{{ (index . 0).String }}">{{ (index . 1).String }}</option>
+ {{ end }}
+ </select></p>
+ <p><label>checker</label><select name="checker_id">
+ {{ range $node := .Content.checkers.Rows }}
+ <option value="{{ (index . 0).String }}">{{ (index . 1).String }}</option>
+ {{ end }}
+ </select></p>
+ <p><label>interval</label><input type="integer" name="interval" value="300" /></p>
+ <fieldset>
+ <legend>options</legend>
+ <!-- TODO implement setting options -->
+ </fieldset>
+ <p><label>message</label><textarea name="message"></textarea></p>
+ <p><button type="submit" name="type" value="check">create</button></p>
+ </form>
+ </details>
+ <details>
+ <summary>nodes</summary>
+ <details>
+ <summary>create new node</summary>
+ <form action="/create" method="POST">
+ <p><label>name</label><input name="name" /></p>
+ <p><label>message</label><textarea name="message"></textarea></p>
+ <p><button type="submit" name="type" value="node">create</button></p>
+ </form>
+ </details>
+ {{ template "rows_to_table" .Content.nodes }}
+ </details>
+ <details>
+ <summary>commands</summary>
+ <details>
+ <summary>create new command</summary>
+ <form action="/create" method="POST">
+ <p><label>name</label><input name="name" /></p>
+ <p><label>command</label><textarea name="command"></textarea></p>
+ <p><label>message</label><textarea name="message"></textarea></p>
+ <p><button type="submit" name="type" value="command">create</button></p>
+ </form>
+ </details>
+ {{ template "rows_to_table" .Content.commands }}
+ </details>
+ <details>
+ <summary>checkers</summary>
+ <details>
+ <summary>create new checker instance</summary>
+ <form action="/create" method="POST">
+ <p><label>name</label><input name="name" /></p>
+ <p><label>description</label><textarea name="description"></textarea></p>
+ <p><button type="submit" name="type" value="checker">create</button></p>
+ </form>
+ </details>
+ {{ template "rows_to_table" .Content.checkers }}
+ </details>
+ <details>
+ <summary>notifier</summary>
+ <details>
+ <summary>create new notifier</summary>
+ <form action="/create" method="POST">
+ <p><label>name</label><input name="name" /></p>
+ <p><label>settings</label><textarea name="settings">{}</textarea></p>
+ <p><button type="submit" name="type" value="notifier">create</button></p>
+ </form>
+ </details>
+ {{ template "rows_to_table" .Content.notifier }}
+ </details>
+</section>
+{{ template "footer" . }}
diff --git a/cmd/monfront/templates/header.html b/cmd/monfront/templates/header.html
index c31a43c..aa8fe4b 100644
--- a/cmd/monfront/templates/header.html
+++ b/cmd/monfront/templates/header.html
@@ -92,6 +92,7 @@
<li><a href="/">home</a></li>
<li><a href="/checks?filter-state=1&filter-ack=false">checks</a></li>
<li><a href="/groups">groups</a></li>
+ <li><a href="/create">create</a></li>
</ul>
</nav>
{{ if .Error }}<div class="error">{{ .Error }}</div>{{ end }}
diff --git a/cmd/monfront/templates/rows_to_table.html b/cmd/monfront/templates/rows_to_table.html
new file mode 100644
index 0000000..04add21
--- /dev/null
+++ b/cmd/monfront/templates/rows_to_table.html
@@ -0,0 +1,19 @@
+ <table>
+ <tr>
+ {{ range $col := .Columns }}
+ <th>{{ $col }}</th>
+ {{ end }}
+ <th></th>
+ </tr>
+ {{ range $row := .Rows }}
+ <tr>
+ {{ range $col := $row }}
+ <td>{{ if $col.Valid }}{{ $col.String }}{{ end }}</td>
+ {{ end }}
+ <td>
+ <button name="update" value="{{ (index $row 0).String }}">update</button>
+ <button name="delete" value="{{ (index $row 0).String }}">delete</button>
+ </td>
+ </tr>
+ {{ end }}
+ </table>