This commit is contained in:
@@ -2,6 +2,7 @@ package httpapp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"gitea.avt.data-center.id/othman.suseno/atlas/internal/models"
|
||||
@@ -9,88 +10,279 @@ import (
|
||||
|
||||
// pathParam is now in router_helpers.go
|
||||
|
||||
// Disk Handlers
|
||||
func (a *App) handleListDisks(w http.ResponseWriter, r *http.Request) {
|
||||
disks, err := a.zfs.ListDisks()
|
||||
if err != nil {
|
||||
log.Printf("list disks error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, disks)
|
||||
}
|
||||
|
||||
// ZFS Pool Handlers
|
||||
func (a *App) handleListPools(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO: Implement ZFS pool listing
|
||||
pools := []models.Pool{} // Stub
|
||||
pools, err := a.zfs.ListPools()
|
||||
if err != nil {
|
||||
log.Printf("list pools error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
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"})
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
VDEVs []string `json:"vdevs"`
|
||||
Options map[string]string `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name == "" || len(req.VDEVs) == 0 {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "name and vdevs are required"})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Options == nil {
|
||||
req.Options = make(map[string]string)
|
||||
}
|
||||
|
||||
if err := a.zfs.CreatePool(req.Name, req.VDEVs, req.Options); err != nil {
|
||||
log.Printf("create pool error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.zfs.GetPool(req.Name)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusCreated, map[string]string{"message": "pool created", "name": req.Name})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusCreated, pool)
|
||||
}
|
||||
|
||||
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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "pool name required"})
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := a.zfs.GetPool(name)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, pool)
|
||||
}
|
||||
|
||||
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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "pool name required"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.zfs.DestroyPool(name); err != nil {
|
||||
log.Printf("destroy pool error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]string{"message": "pool destroyed", "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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "pool name required"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.zfs.ScrubPool(name); err != nil {
|
||||
log.Printf("scrub pool error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]string{"message": "scrub started", "pool": name})
|
||||
}
|
||||
|
||||
// Dataset Handlers
|
||||
func (a *App) handleListDatasets(w http.ResponseWriter, r *http.Request) {
|
||||
datasets := []models.Dataset{} // Stub
|
||||
pool := r.URL.Query().Get("pool")
|
||||
datasets, err := a.zfs.ListDatasets(pool)
|
||||
if err != nil {
|
||||
log.Printf("list datasets error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
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"`
|
||||
Name string `json:"name"`
|
||||
Options map[string]string `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"})
|
||||
return
|
||||
}
|
||||
// TODO: Implement dataset creation
|
||||
writeJSON(w, http.StatusNotImplemented, map[string]string{"error": "not implemented"})
|
||||
|
||||
if req.Name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "dataset name is required"})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Options == nil {
|
||||
req.Options = make(map[string]string)
|
||||
}
|
||||
|
||||
if err := a.zfs.CreateDataset(req.Name, req.Options); err != nil {
|
||||
log.Printf("create dataset error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusCreated, map[string]string{"message": "dataset created", "name": req.Name})
|
||||
}
|
||||
|
||||
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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "dataset name required"})
|
||||
return
|
||||
}
|
||||
|
||||
datasets, err := a.zfs.ListDatasets("")
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
for _, ds := range datasets {
|
||||
if ds.Name == name {
|
||||
writeJSON(w, http.StatusOK, ds)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusNotFound, map[string]string{"error": "dataset not found"})
|
||||
}
|
||||
|
||||
func (a *App) handleUpdateDataset(w http.ResponseWriter, r *http.Request) {
|
||||
name := pathParam(r, "/api/v1/datasets/")
|
||||
// TODO: Implement dataset property updates
|
||||
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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "dataset name required"})
|
||||
return
|
||||
}
|
||||
|
||||
recursive := r.URL.Query().Get("recursive") == "true"
|
||||
|
||||
if err := a.zfs.DestroyDataset(name, recursive); err != nil {
|
||||
log.Printf("destroy dataset error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]string{"message": "dataset destroyed", "name": name})
|
||||
}
|
||||
|
||||
// ZVOL Handlers
|
||||
func (a *App) handleListZVOLs(w http.ResponseWriter, r *http.Request) {
|
||||
zvols := []models.ZVOL{} // Stub
|
||||
pool := r.URL.Query().Get("pool")
|
||||
zvols, err := a.zfs.ListZVOLs(pool)
|
||||
if err != nil {
|
||||
log.Printf("list zvols error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
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"})
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"` // in bytes
|
||||
Options map[string]string `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name == "" || req.Size == 0 {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "name and size are required"})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Options == nil {
|
||||
req.Options = make(map[string]string)
|
||||
}
|
||||
|
||||
if err := a.zfs.CreateZVOL(req.Name, req.Size, req.Options); err != nil {
|
||||
log.Printf("create zvol error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusCreated, map[string]string{"message": "zvol created", "name": req.Name})
|
||||
}
|
||||
|
||||
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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "zvol name required"})
|
||||
return
|
||||
}
|
||||
|
||||
zvols, err := a.zfs.ListZVOLs("")
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
for _, zvol := range zvols {
|
||||
if zvol.Name == name {
|
||||
writeJSON(w, http.StatusOK, zvol)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusNotFound, map[string]string{"error": "zvol not found"})
|
||||
}
|
||||
|
||||
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})
|
||||
if name == "" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "zvol name required"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.zfs.DestroyZVOL(name); err != nil {
|
||||
log.Printf("destroy zvol error: %v", err)
|
||||
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]string{"message": "zvol destroyed", "name": name})
|
||||
}
|
||||
|
||||
// Snapshot Handlers
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"gitea.avt.data-center.id/othman.suseno/atlas/internal/zfs"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -18,6 +20,7 @@ type App struct {
|
||||
cfg Config
|
||||
tmpl *template.Template
|
||||
mux *http.ServeMux
|
||||
zfs *zfs.Service
|
||||
}
|
||||
|
||||
func New(cfg Config) (*App, error) {
|
||||
@@ -37,6 +40,7 @@ func New(cfg Config) (*App, error) {
|
||||
cfg: cfg,
|
||||
tmpl: tmpl,
|
||||
mux: http.NewServeMux(),
|
||||
zfs: zfs.New(),
|
||||
}
|
||||
|
||||
a.routes()
|
||||
|
||||
@@ -15,6 +15,10 @@ func (a *App) routes() {
|
||||
a.mux.HandleFunc("/metrics", a.handleMetrics)
|
||||
|
||||
// API v1 routes - ZFS Management
|
||||
a.mux.HandleFunc("/api/v1/disks", methodHandler(
|
||||
func(w http.ResponseWriter, r *http.Request) { a.handleListDisks(w, r) },
|
||||
nil, nil, nil, nil,
|
||||
))
|
||||
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) },
|
||||
|
||||
Reference in New Issue
Block a user