add function to s3

This commit is contained in:
2026-01-10 05:36:15 +00:00
parent 7b91e0fd24
commit 8a3ff6a12c
19 changed files with 3715 additions and 134 deletions

View File

@@ -10,11 +10,12 @@ import (
// Config represents the application configuration
type Config struct {
Server ServerConfig `yaml:"server"`
Database DatabaseConfig `yaml:"database"`
Auth AuthConfig `yaml:"auth"`
Logging LoggingConfig `yaml:"logging"`
Security SecurityConfig `yaml:"security"`
Server ServerConfig `yaml:"server"`
Database DatabaseConfig `yaml:"database"`
Auth AuthConfig `yaml:"auth"`
Logging LoggingConfig `yaml:"logging"`
Security SecurityConfig `yaml:"security"`
ObjectStorage ObjectStorageConfig `yaml:"object_storage"`
}
// ServerConfig holds HTTP server configuration
@@ -96,6 +97,14 @@ type SecurityHeadersConfig struct {
Enabled bool `yaml:"enabled"`
}
// ObjectStorageConfig holds MinIO configuration
type ObjectStorageConfig struct {
Endpoint string `yaml:"endpoint"`
AccessKey string `yaml:"access_key"`
SecretKey string `yaml:"secret_key"`
UseSSL bool `yaml:"use_ssl"`
}
// Load reads configuration from file and environment variables
func Load(path string) (*Config, error) {
cfg := DefaultConfig()

View File

@@ -0,0 +1,22 @@
-- Migration: Object Storage Configuration
-- Description: Creates table for storing MinIO object storage configuration
-- Date: 2026-01-09
CREATE TABLE IF NOT EXISTS object_storage_config (
id SERIAL PRIMARY KEY,
dataset_path VARCHAR(255) NOT NULL UNIQUE,
mount_point VARCHAR(512) NOT NULL,
pool_name VARCHAR(255) NOT NULL,
dataset_name VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_object_storage_config_pool_name ON object_storage_config(pool_name);
CREATE INDEX IF NOT EXISTS idx_object_storage_config_updated_at ON object_storage_config(updated_at);
COMMENT ON TABLE object_storage_config IS 'Stores MinIO object storage configuration, linking to ZFS datasets';
COMMENT ON COLUMN object_storage_config.dataset_path IS 'Full ZFS dataset path (e.g., pool/dataset)';
COMMENT ON COLUMN object_storage_config.mount_point IS 'Mount point path for the dataset';
COMMENT ON COLUMN object_storage_config.pool_name IS 'ZFS pool name';
COMMENT ON COLUMN object_storage_config.dataset_name IS 'ZFS dataset name';

View File

@@ -13,6 +13,7 @@ import (
"github.com/atlasos/calypso/internal/common/logger"
"github.com/atlasos/calypso/internal/iam"
"github.com/atlasos/calypso/internal/monitoring"
"github.com/atlasos/calypso/internal/object_storage"
"github.com/atlasos/calypso/internal/scst"
"github.com/atlasos/calypso/internal/shares"
"github.com/atlasos/calypso/internal/storage"
@@ -211,6 +212,45 @@ func NewRouter(cfg *config.Config, db *database.DB, log *logger.Logger) *gin.Eng
sharesGroup.DELETE("/:id", requirePermission("storage", "write"), sharesHandler.DeleteShare)
}
// Object Storage (MinIO)
// Initialize MinIO service if configured
if cfg.ObjectStorage.Endpoint != "" {
objectStorageService, err := object_storage.NewService(
cfg.ObjectStorage.Endpoint,
cfg.ObjectStorage.AccessKey,
cfg.ObjectStorage.SecretKey,
log,
)
if err != nil {
log.Error("Failed to initialize MinIO service", "error", err)
} else {
objectStorageHandler := object_storage.NewHandler(objectStorageService, db, log)
objectStorageGroup := protected.Group("/object-storage")
objectStorageGroup.Use(requirePermission("storage", "read"))
{
// Setup endpoints
objectStorageGroup.GET("/setup/datasets", objectStorageHandler.GetAvailableDatasets)
objectStorageGroup.GET("/setup/current", objectStorageHandler.GetCurrentSetup)
objectStorageGroup.POST("/setup", requirePermission("storage", "write"), objectStorageHandler.SetupObjectStorage)
objectStorageGroup.PUT("/setup", requirePermission("storage", "write"), objectStorageHandler.UpdateObjectStorage)
// Bucket endpoints
objectStorageGroup.GET("/buckets", objectStorageHandler.ListBuckets)
objectStorageGroup.GET("/buckets/:name", objectStorageHandler.GetBucket)
objectStorageGroup.POST("/buckets", requirePermission("storage", "write"), objectStorageHandler.CreateBucket)
objectStorageGroup.DELETE("/buckets/:name", requirePermission("storage", "write"), objectStorageHandler.DeleteBucket)
// User management routes
objectStorageGroup.GET("/users", objectStorageHandler.ListUsers)
objectStorageGroup.POST("/users", requirePermission("storage", "write"), objectStorageHandler.CreateUser)
objectStorageGroup.DELETE("/users/:access_key", requirePermission("storage", "write"), objectStorageHandler.DeleteUser)
// Service account (access key) management routes
objectStorageGroup.GET("/service-accounts", objectStorageHandler.ListServiceAccounts)
objectStorageGroup.POST("/service-accounts", requirePermission("storage", "write"), objectStorageHandler.CreateServiceAccount)
objectStorageGroup.DELETE("/service-accounts/:access_key", requirePermission("storage", "write"), objectStorageHandler.DeleteServiceAccount)
}
}
}
// SCST
scstHandler := scst.NewHandler(db, log)
scstGroup := protected.Group("/scst")
@@ -307,8 +347,9 @@ func NewRouter(cfg *config.Config, db *database.DB, log *logger.Logger) *gin.Eng
systemGroup.GET("/logs", systemHandler.GetSystemLogs)
systemGroup.GET("/network/throughput", systemHandler.GetNetworkThroughput)
systemGroup.POST("/support-bundle", systemHandler.GenerateSupportBundle)
systemGroup.GET("/interfaces", systemHandler.ListNetworkInterfaces)
systemGroup.PUT("/interfaces/:name", systemHandler.UpdateNetworkInterface)
systemGroup.GET("/interfaces", systemHandler.ListNetworkInterfaces)
systemGroup.GET("/management-ip", systemHandler.GetManagementIPAddress)
systemGroup.PUT("/interfaces/:name", systemHandler.UpdateNetworkInterface)
systemGroup.GET("/ntp", systemHandler.GetNTPSettings)
systemGroup.POST("/ntp", systemHandler.SaveNTPSettings)
systemGroup.POST("/execute", requirePermission("system", "write"), systemHandler.ExecuteCommand)