Commit 8d477c80 authored by ale's avatar ale

Add a debug page showing latest backups

parent 3cf73522
package server
import (
"bytes"
"database/sql"
"html/template"
"io"
"net/http"
"time"
)
var (
latestDatasetsHTML = `<!DOCTYPE html>
<html>
<head>
<title>Tabacco</title>
</head>
<body>
<h1>Tabacco</h1>
<p>Started at {{.StartTime}}.</p>
<h3>Latest backups</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>Time</th>
<th>Host</th>
<th>Dataset</th>
<th>Source</th>
</tr>
</thead>
<tbody>
{{range .Backups}}
<tr>
<td><b>{{.BackupID}}</b></td>
<td>{{.BackupTimestamp}}</td>
<td>{{.BackupHost}}</td>
<td colspan="2"></td>
</tr>
{{range .Datasets}}
<tr>
<td colspan="3"></td>
<td>{{.DatasetID}}</td>
<td>{{.DatasetSource}}</td>
</tr>
{{end}}
{{end}}
</tbody>
</table>
</body>
</html>`
latestDatasetsTemplate *template.Template
startTime time.Time
)
func init() {
latestDatasetsTemplate = template.Must(
template.New("latest").Parse(latestDatasetsHTML))
startTime = time.Now()
}
type datasetDebug struct {
DatasetID string
DatasetSnapshotID string
DatasetSource string
}
type backupDebug struct {
BackupID string
BackupTimestamp time.Time
BackupHost string
Datasets []*datasetDebug
}
func (s *httpServer) handleDebug(w http.ResponseWriter, r *http.Request) {
backupMap := make(map[string]*backupDebug)
var backups []*backupDebug
err := retryBusy(r.Context(), func() error {
return withTX(r.Context(), s.db, func(tx *sql.Tx) error {
stmt := s.stmts.get(tx, "get_latest_datasets")
defer stmt.Close()
rows, err := stmt.Query(10)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var bd backupDebug
var dd datasetDebug
if err := rows.Scan(
&bd.BackupID, &bd.BackupTimestamp, &bd.BackupHost,
&dd.DatasetID, &dd.DatasetSnapshotID, &dd.DatasetSource,
); err != nil {
return err
}
b, ok := backupMap[bd.BackupID]
if !ok {
b = &bd
backupMap[bd.BackupID] = b
backups = append(backups, b)
}
b.Datasets = append(b.Datasets, &dd)
}
return rows.Err()
})
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var buf bytes.Buffer
if err := latestDatasetsTemplate.Execute(&buf, map[string]interface{}{
"Backups": backups,
"StartTime": startTime,
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.Copy(w, &buf) // nolint
}
package server
import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
)
func TestDebugPage(t *testing.T) {
defer os.Remove(DBFILE)
svc, err := New("sqlite3", DBFILE)
if err != nil {
t.Fatal(err)
}
defer svc.Close()
addTestEntry(t, svc, "1234", "host1", "file/dataset1")
httpSrv := &httpServer{svc}
srv := httptest.NewServer(httpSrv.Handler())
resp, err := http.Get(srv.URL)
if err != nil {
t.Fatalf("Get(): %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Errorf("Get(): %s", resp.Status)
io.Copy(os.Stderr, resp.Body) // nolint
}
}
......@@ -52,6 +52,13 @@ func (s *httpServer) Handler() http.Handler {
m := http.NewServeMux()
m.HandleFunc("/api/add_dataset", s.handleAddDataset)
m.HandleFunc("/api/find_atoms", s.handleFindAtoms)
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
s.handleDebug(w, r)
})
return m
}
......
......@@ -169,6 +169,27 @@ var statements = map[string]string{
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?
)
`,
"get_latest_atoms": `
SELECT
backup_id, backup_timestamp, backup_host,
dataset_id, dataset_snapshot_id, dataset_source,
atom_name, atom_path, atom_full_path
FROM log
ORDER BY backup_timestamp DESC
LIMIT ?
`,
"get_latest_datasets": `
SELECT
backup_id, backup_timestamp, backup_host,
dataset_id, dataset_snapshot_id, dataset_source
FROM log
WHERE backup_id IN (
SELECT backup_id
FROM log
GROUP BY backup_id, backup_timestamp
ORDER BY backup_timestamp DESC
LIMIT ?)
`,
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment