286 lines
9.5 KiB
Go
286 lines
9.5 KiB
Go
package object_storage
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/atlasos/calypso/internal/common/database"
|
|
"github.com/atlasos/calypso/internal/common/logger"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// Handler handles HTTP requests for object storage
|
|
type Handler struct {
|
|
service *Service
|
|
setupService *SetupService
|
|
logger *logger.Logger
|
|
}
|
|
|
|
// NewHandler creates a new object storage handler
|
|
func NewHandler(service *Service, db *database.DB, log *logger.Logger) *Handler {
|
|
return &Handler{
|
|
service: service,
|
|
setupService: NewSetupService(db, log),
|
|
logger: log,
|
|
}
|
|
}
|
|
|
|
// ListBuckets lists all buckets
|
|
func (h *Handler) ListBuckets(c *gin.Context) {
|
|
buckets, err := h.service.ListBuckets(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("Failed to list buckets", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list buckets: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"buckets": buckets})
|
|
}
|
|
|
|
// GetBucket gets bucket information
|
|
func (h *Handler) GetBucket(c *gin.Context) {
|
|
bucketName := c.Param("name")
|
|
|
|
bucket, err := h.service.GetBucketStats(c.Request.Context(), bucketName)
|
|
if err != nil {
|
|
h.logger.Error("Failed to get bucket", "bucket", bucketName, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get bucket: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, bucket)
|
|
}
|
|
|
|
// CreateBucketRequest represents a request to create a bucket
|
|
type CreateBucketRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
}
|
|
|
|
// CreateBucket creates a new bucket
|
|
func (h *Handler) CreateBucket(c *gin.Context) {
|
|
var req CreateBucketRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
h.logger.Error("Invalid create bucket request", "error", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if err := h.service.CreateBucket(c.Request.Context(), req.Name); err != nil {
|
|
h.logger.Error("Failed to create bucket", "bucket", req.Name, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create bucket: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, gin.H{"message": "bucket created successfully", "name": req.Name})
|
|
}
|
|
|
|
// DeleteBucket deletes a bucket
|
|
func (h *Handler) DeleteBucket(c *gin.Context) {
|
|
bucketName := c.Param("name")
|
|
|
|
if err := h.service.DeleteBucket(c.Request.Context(), bucketName); err != nil {
|
|
h.logger.Error("Failed to delete bucket", "bucket", bucketName, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete bucket: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "bucket deleted successfully"})
|
|
}
|
|
|
|
// GetAvailableDatasets gets all available pools and datasets for object storage setup
|
|
func (h *Handler) GetAvailableDatasets(c *gin.Context) {
|
|
datasets, err := h.setupService.GetAvailableDatasets(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("Failed to get available datasets", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get available datasets: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"pools": datasets})
|
|
}
|
|
|
|
// SetupObjectStorageRequest represents a request to setup object storage
|
|
type SetupObjectStorageRequest struct {
|
|
PoolName string `json:"pool_name" binding:"required"`
|
|
DatasetName string `json:"dataset_name" binding:"required"`
|
|
CreateNew bool `json:"create_new"`
|
|
}
|
|
|
|
// SetupObjectStorage configures object storage with a ZFS dataset
|
|
func (h *Handler) SetupObjectStorage(c *gin.Context) {
|
|
var req SetupObjectStorageRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
h.logger.Error("Invalid setup request", "error", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
setupReq := SetupRequest{
|
|
PoolName: req.PoolName,
|
|
DatasetName: req.DatasetName,
|
|
CreateNew: req.CreateNew,
|
|
}
|
|
|
|
result, err := h.setupService.SetupObjectStorage(c.Request.Context(), setupReq)
|
|
if err != nil {
|
|
h.logger.Error("Failed to setup object storage", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to setup object storage: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, result)
|
|
}
|
|
|
|
// GetCurrentSetup gets the current object storage configuration
|
|
func (h *Handler) GetCurrentSetup(c *gin.Context) {
|
|
setup, err := h.setupService.GetCurrentSetup(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("Failed to get current setup", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get current setup: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if setup == nil {
|
|
c.JSON(http.StatusOK, gin.H{"configured": false})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"configured": true, "setup": setup})
|
|
}
|
|
|
|
// UpdateObjectStorage updates the object storage configuration
|
|
func (h *Handler) UpdateObjectStorage(c *gin.Context) {
|
|
var req SetupObjectStorageRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
h.logger.Error("Invalid update request", "error", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
setupReq := SetupRequest{
|
|
PoolName: req.PoolName,
|
|
DatasetName: req.DatasetName,
|
|
CreateNew: req.CreateNew,
|
|
}
|
|
|
|
result, err := h.setupService.UpdateObjectStorage(c.Request.Context(), setupReq)
|
|
if err != nil {
|
|
h.logger.Error("Failed to update object storage", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update object storage: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, result)
|
|
}
|
|
|
|
// ListUsers lists all IAM users
|
|
func (h *Handler) ListUsers(c *gin.Context) {
|
|
users, err := h.service.ListUsers(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("Failed to list users", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list users: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"users": users})
|
|
}
|
|
|
|
// CreateUserRequest represents a request to create a user
|
|
type CreateUserRequest struct {
|
|
AccessKey string `json:"access_key" binding:"required"`
|
|
SecretKey string `json:"secret_key" binding:"required"`
|
|
}
|
|
|
|
// CreateUser creates a new IAM user
|
|
func (h *Handler) CreateUser(c *gin.Context) {
|
|
var req CreateUserRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
h.logger.Error("Invalid create user request", "error", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if err := h.service.CreateUser(c.Request.Context(), req.AccessKey, req.SecretKey); err != nil {
|
|
h.logger.Error("Failed to create user", "access_key", req.AccessKey, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, gin.H{"message": "user created successfully", "access_key": req.AccessKey})
|
|
}
|
|
|
|
// DeleteUser deletes an IAM user
|
|
func (h *Handler) DeleteUser(c *gin.Context) {
|
|
accessKey := c.Param("access_key")
|
|
|
|
if err := h.service.DeleteUser(c.Request.Context(), accessKey); err != nil {
|
|
h.logger.Error("Failed to delete user", "access_key", accessKey, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "user deleted successfully"})
|
|
}
|
|
|
|
// ListServiceAccounts lists all service accounts (access keys)
|
|
func (h *Handler) ListServiceAccounts(c *gin.Context) {
|
|
accounts, err := h.service.ListServiceAccounts(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("Failed to list service accounts", "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list service accounts: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"service_accounts": accounts})
|
|
}
|
|
|
|
// CreateServiceAccountRequest represents a request to create a service account
|
|
type CreateServiceAccountRequest struct {
|
|
ParentUser string `json:"parent_user" binding:"required"`
|
|
Policy string `json:"policy,omitempty"`
|
|
Expiration *string `json:"expiration,omitempty"` // ISO 8601 format
|
|
}
|
|
|
|
// CreateServiceAccount creates a new service account (access key)
|
|
func (h *Handler) CreateServiceAccount(c *gin.Context) {
|
|
var req CreateServiceAccountRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
h.logger.Error("Invalid create service account request", "error", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
var expiration *time.Time
|
|
if req.Expiration != nil {
|
|
exp, err := time.Parse(time.RFC3339, *req.Expiration)
|
|
if err != nil {
|
|
h.logger.Error("Invalid expiration format", "error", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid expiration format, use ISO 8601 (RFC3339)"})
|
|
return
|
|
}
|
|
expiration = &exp
|
|
}
|
|
|
|
account, err := h.service.CreateServiceAccount(c.Request.Context(), req.ParentUser, req.Policy, expiration)
|
|
if err != nil {
|
|
h.logger.Error("Failed to create service account", "parent_user", req.ParentUser, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create service account: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, account)
|
|
}
|
|
|
|
// DeleteServiceAccount deletes a service account
|
|
func (h *Handler) DeleteServiceAccount(c *gin.Context) {
|
|
accessKey := c.Param("access_key")
|
|
|
|
if err := h.service.DeleteServiceAccount(c.Request.Context(), accessKey); err != nil {
|
|
h.logger.Error("Failed to delete service account", "access_key", accessKey, "error", err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete service account: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "service account deleted successfully"})
|
|
}
|