add api framework
Some checks failed
CI / test-build (push) Failing after 59s

This commit is contained in:
2025-12-14 22:15:56 +07:00
parent f4683eeb73
commit a6da313dfc
13 changed files with 915 additions and 84 deletions

View File

@@ -0,0 +1,280 @@
package httpapp
import (
"encoding/json"
"net/http"
"gitea.avt.data-center.id/othman.suseno/atlas/internal/models"
)
// pathParam is now in router_helpers.go
// ZFS Pool Handlers
func (a *App) handleListPools(w http.ResponseWriter, r *http.Request) {
// TODO: Implement ZFS pool listing
pools := []models.Pool{} // Stub
writeJSON(w, http.StatusOK, pools)
}
func (a *App) handleCreatePool(w http.ResponseWriter, r *http.Request) {
// TODO: Implement pool creation
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetPool(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/pools/")
// TODO: Implement pool retrieval
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
func (a *App) handleDeletePool(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/pools/")
// TODO: Implement pool deletion
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
func (a *App) handleScrubPool(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/pools/")
// TODO: Implement pool scrub
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
// Dataset Handlers
func (a *App) handleListDatasets(w http.ResponseWriter, r *http.Request) {
datasets := []models.Dataset{} // Stub
writeJSON(w, http.StatusOK, datasets)
}
func (a *App) handleCreateDataset(w http.ResponseWriter, r *http.Request) {
var req struct {
Name string `json:"name"`
Pool string `json:"pool"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request"})
return
}
// TODO: Implement dataset creation
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetDataset(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/datasets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
func (a *App) handleUpdateDataset(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/datasets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
func (a *App) handleDeleteDataset(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/datasets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
// ZVOL Handlers
func (a *App) handleListZVOLs(w http.ResponseWriter, r *http.Request) {
zvols := []models.ZVOL{} // Stub
writeJSON(w, http.StatusOK, zvols)
}
func (a *App) handleCreateZVOL(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetZVOL(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/zvols/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
func (a *App) handleDeleteZVOL(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/zvols/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
// Snapshot Handlers
func (a *App) handleListSnapshots(w http.ResponseWriter, r *http.Request) {
snapshots := []models.Snapshot{} // Stub
writeJSON(w, http.StatusOK, snapshots)
}
func (a *App) handleCreateSnapshot(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetSnapshot(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/snapshots/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
func (a *App) handleDeleteSnapshot(w http.ResponseWriter, r *http.Request) {
name := pathParam(r, "/api/v1/snapshots/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "name": name})
}
// Snapshot Policy Handlers
func (a *App) handleListSnapshotPolicies(w http.ResponseWriter, r *http.Request) {
policies := []models.SnapshotPolicy{} // Stub
writeJSON(w, http.StatusOK, policies)
}
func (a *App) handleCreateSnapshotPolicy(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetSnapshotPolicy(w http.ResponseWriter, r *http.Request) {
dataset := pathParam(r, "/api/v1/snapshot-policies/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "dataset": dataset})
}
func (a *App) handleUpdateSnapshotPolicy(w http.ResponseWriter, r *http.Request) {
dataset := pathParam(r, "/api/v1/snapshot-policies/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "dataset": dataset})
}
func (a *App) handleDeleteSnapshotPolicy(w http.ResponseWriter, r *http.Request) {
dataset := pathParam(r, "/api/v1/snapshot-policies/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "dataset": dataset})
}
// SMB Share Handlers
func (a *App) handleListSMBShares(w http.ResponseWriter, r *http.Request) {
shares := []models.SMBShare{} // Stub
writeJSON(w, http.StatusOK, shares)
}
func (a *App) handleCreateSMBShare(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetSMBShare(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/shares/smb/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleUpdateSMBShare(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/shares/smb/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleDeleteSMBShare(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/shares/smb/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
// NFS Export Handlers
func (a *App) handleListNFSExports(w http.ResponseWriter, r *http.Request) {
exports := []models.NFSExport{} // Stub
writeJSON(w, http.StatusOK, exports)
}
func (a *App) handleCreateNFSExport(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetNFSExport(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/exports/nfs/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleUpdateNFSExport(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/exports/nfs/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleDeleteNFSExport(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/exports/nfs/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
// iSCSI Handlers
func (a *App) handleListISCSITargets(w http.ResponseWriter, r *http.Request) {
targets := []models.ISCSITarget{} // Stub
writeJSON(w, http.StatusOK, targets)
}
func (a *App) handleCreateISCSITarget(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetISCSITarget(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/iscsi/targets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleUpdateISCSITarget(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/iscsi/targets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleDeleteISCSITarget(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/iscsi/targets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleAddLUN(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/iscsi/targets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleRemoveLUN(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/iscsi/targets/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
// Job Handlers
func (a *App) handleListJobs(w http.ResponseWriter, r *http.Request) {
jobs := []models.Job{} // Stub
writeJSON(w, http.StatusOK, jobs)
}
func (a *App) handleGetJob(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/jobs/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleCancelJob(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/jobs/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
// Auth Handlers (stubs)
func (a *App) handleLogin(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleLogout(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"message": "logged out"})
}
// User Handlers
func (a *App) handleListUsers(w http.ResponseWriter, r *http.Request) {
users := []models.User{} // Stub
writeJSON(w, http.StatusOK, users)
}
func (a *App) handleCreateUser(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
}
func (a *App) handleGetUser(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/users/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleUpdateUser(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/users/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
func (a *App) handleDeleteUser(w http.ResponseWriter, r *http.Request) {
id := pathParam(r, "/api/v1/users/")
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented", "id": id})
}
// Audit Log Handlers
func (a *App) handleListAuditLogs(w http.ResponseWriter, r *http.Request) {
logs := []models.AuditLog{} // Stub
writeJSON(w, http.StatusOK, logs)
}

View File

@@ -48,18 +48,7 @@ func (a *App) Router() http.Handler {
return requestID(logging(a.mux))
}
func (a *App) routes() {
// Static
fs := http.FileServer(http.Dir(a.cfg.StaticDir))
a.mux.Handle("/static/", http.StripPrefix("/static/", fs))
// Core pages
a.mux.HandleFunc("/", a.handleDashboard)
// Health & metrics
a.mux.HandleFunc("/healthz", a.handleHealthz)
a.mux.HandleFunc("/metrics", a.handleMetrics)
}
// routes() is now in routes.go
func parseTemplates(dir string) (*template.Template, error) {
pattern := filepath.Join(dir, "*.html")

View File

@@ -30,12 +30,12 @@ func (a *App) handleMetrics(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; version=0.0.4")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(
`# HELP pluto_build_info Build info
# TYPE pluto_build_info gauge
pluto_build_info{version="v0.1.0-dev"} 1
# HELP pluto_up Whether the pluto-api process is up
# TYPE pluto_up gauge
pluto_up 1
`# HELP atlas_build_info Build info
# TYPE atlas_build_info gauge
atlas_build_info{version="v0.1.0-dev"} 1
# HELP atlas_up Whether the atlas-api process is up
# TYPE atlas_up gauge
atlas_up 1
`,
))
}

View File

@@ -0,0 +1,185 @@
package httpapp
import (
"net/http"
"strings"
)
// methodHandler routes requests based on HTTP method
func methodHandler(get, post, put, delete, patch http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
if get != nil {
get(w, r)
} else {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
case http.MethodPost:
if post != nil {
post(w, r)
} else {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
case http.MethodPut:
if put != nil {
put(w, r)
} else {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
case http.MethodDelete:
if delete != nil {
delete(w, r)
} else {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
case http.MethodPatch:
if patch != nil {
patch(w, r)
} else {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
}
}
// pathParam extracts the last segment from a path
func pathParam(r *http.Request, prefix string) string {
path := strings.TrimPrefix(r.URL.Path, prefix)
path = strings.Trim(path, "/")
parts := strings.Split(path, "/")
if len(parts) > 0 {
return parts[len(parts)-1]
}
return ""
}
// handlePoolOps routes pool operations by method
func (a *App) handlePoolOps(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/scrub") {
if r.Method == http.MethodPost {
a.handleScrubPool(w, r)
return
}
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetPool(w, r) },
nil,
nil,
func(w http.ResponseWriter, r *http.Request) { a.handleDeletePool(w, r) },
nil,
)(w, r)
}
// handleDatasetOps routes dataset operations by method
func (a *App) handleDatasetOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetDataset(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateDataset(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleUpdateDataset(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteDataset(w, r) },
nil,
)(w, r)
}
// handleZVOLOps routes ZVOL operations by method
func (a *App) handleZVOLOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetZVOL(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateZVOL(w, r) },
nil,
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteZVOL(w, r) },
nil,
)(w, r)
}
// handleSnapshotOps routes snapshot operations by method
func (a *App) handleSnapshotOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetSnapshot(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateSnapshot(w, r) },
nil,
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteSnapshot(w, r) },
nil,
)(w, r)
}
// handleSnapshotPolicyOps routes snapshot policy operations by method
func (a *App) handleSnapshotPolicyOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetSnapshotPolicy(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateSnapshotPolicy(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleUpdateSnapshotPolicy(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteSnapshotPolicy(w, r) },
nil,
)(w, r)
}
// handleSMBShareOps routes SMB share operations by method
func (a *App) handleSMBShareOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetSMBShare(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateSMBShare(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleUpdateSMBShare(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteSMBShare(w, r) },
nil,
)(w, r)
}
// handleNFSExportOps routes NFS export operations by method
func (a *App) handleNFSExportOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetNFSExport(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateNFSExport(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleUpdateNFSExport(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteNFSExport(w, r) },
nil,
)(w, r)
}
// handleISCSITargetOps routes iSCSI target operations by method
func (a *App) handleISCSITargetOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetISCSITarget(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateISCSITarget(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleUpdateISCSITarget(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteISCSITarget(w, r) },
nil,
)(w, r)
}
// handleJobOps routes job operations by method
func (a *App) handleJobOps(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/cancel") {
if r.Method == http.MethodPost {
a.handleCancelJob(w, r)
return
}
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetJob(w, r) },
nil,
nil,
nil,
nil,
)(w, r)
}
// handleUserOps routes user operations by method
func (a *App) handleUserOps(w http.ResponseWriter, r *http.Request) {
methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleGetUser(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateUser(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleUpdateUser(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleDeleteUser(w, r) },
nil,
)(w, r)
}

104
internal/httpapp/routes.go Normal file
View File

@@ -0,0 +1,104 @@
package httpapp
import "net/http"
func (a *App) routes() {
// Static files
fs := http.FileServer(http.Dir(a.cfg.StaticDir))
a.mux.Handle("/static/", http.StripPrefix("/static/", fs))
// Web UI
a.mux.HandleFunc("/", a.handleDashboard)
// Health & metrics
a.mux.HandleFunc("/healthz", a.handleHealthz)
a.mux.HandleFunc("/metrics", a.handleMetrics)
// API v1 routes - ZFS Management
a.mux.HandleFunc("/api/v1/pools", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListPools(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreatePool(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/pools/", a.handlePoolOps)
a.mux.HandleFunc("/api/v1/datasets", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListDatasets(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateDataset(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/datasets/", a.handleDatasetOps)
a.mux.HandleFunc("/api/v1/zvols", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListZVOLs(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateZVOL(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/zvols/", a.handleZVOLOps)
// Snapshot Management
a.mux.HandleFunc("/api/v1/snapshots", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListSnapshots(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateSnapshot(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/snapshots/", a.handleSnapshotOps)
a.mux.HandleFunc("/api/v1/snapshot-policies", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListSnapshotPolicies(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateSnapshotPolicy(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/snapshot-policies/", a.handleSnapshotPolicyOps)
// Storage Services - SMB
a.mux.HandleFunc("/api/v1/shares/smb", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListSMBShares(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateSMBShare(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/shares/smb/", a.handleSMBShareOps)
// Storage Services - NFS
a.mux.HandleFunc("/api/v1/exports/nfs", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListNFSExports(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateNFSExport(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/exports/nfs/", a.handleNFSExportOps)
// Storage Services - iSCSI
a.mux.HandleFunc("/api/v1/iscsi/targets", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListISCSITargets(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateISCSITarget(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/iscsi/targets/", a.handleISCSITargetOps)
// Job Management
a.mux.HandleFunc("/api/v1/jobs", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListJobs(w, r) },
nil, nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/jobs/", a.handleJobOps)
// Authentication & Authorization
a.mux.HandleFunc("/api/v1/auth/login", methodHandler(
nil,
func(w http.ResponseWriter, r *http.Request) { a.handleLogin(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/auth/logout", methodHandler(
nil,
func(w http.ResponseWriter, r *http.Request) { a.handleLogout(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/users", methodHandler(
func(w http.ResponseWriter, r *http.Request) { a.handleListUsers(w, r) },
func(w http.ResponseWriter, r *http.Request) { a.handleCreateUser(w, r) },
nil, nil, nil,
))
a.mux.HandleFunc("/api/v1/users/", a.handleUserOps)
// Audit Logs
a.mux.HandleFunc("/api/v1/audit", a.handleListAuditLogs)
}