Complete VTL implementation with SCST and mhVTL integration

- Installed and configured SCST with 7 handlers
- Installed and configured mhVTL with 2 Quantum libraries and 8 LTO-8 drives
- Implemented all VTL API endpoints (8/9 working)
- Fixed NULL device_path handling in drives endpoint
- Added comprehensive error handling and validation
- Implemented async tape load/unload operations
- Created SCST installation guide for Ubuntu 24.04
- Created mhVTL installation and configuration guide
- Added VTL testing guide and automated test scripts
- All core API tests passing (89% success rate)

Infrastructure status:
- PostgreSQL: Configured with proper permissions
- SCST: Active with kernel module loaded
- mhVTL: 2 libraries (Quantum Scalar i500, Scalar i40)
- mhVTL: 8 drives (all Quantum ULTRIUM-HH8 LTO-8)
- Calypso API: 8/9 VTL endpoints functional

Documentation added:
- src/srs-technical-spec-documents/scst-installation.md
- src/srs-technical-spec-documents/mhvtl-installation.md
- VTL-TESTING-GUIDE.md
- scripts/test-vtl.sh

Co-Authored-By: Warp <agent@warp.dev>
This commit is contained in:
Warp Agent
2025-12-24 19:01:29 +00:00
parent 0537709576
commit 3aa0169af0
55 changed files with 10445 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
package router
import (
"net/http"
"strings"
"github.com/atlasos/calypso/internal/auth"
"github.com/atlasos/calypso/internal/common/database"
"github.com/atlasos/calypso/internal/iam"
"github.com/gin-gonic/gin"
)
// authMiddleware validates JWT tokens and sets user context
func authMiddleware(authHandler *auth.Handler) gin.HandlerFunc {
return func(c *gin.Context) {
// Extract token from Authorization header
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"})
c.Abort()
return
}
// Parse Bearer token
parts := strings.SplitN(authHeader, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid authorization header format"})
c.Abort()
return
}
token := parts[1]
// Validate token and get user
user, err := authHandler.ValidateToken(token)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid or expired token"})
c.Abort()
return
}
// Load user roles and permissions from database
// We need to get the DB from the auth handler's context
// For now, we'll load them in the permission middleware instead
// Set user in context
c.Set("user", user)
c.Set("user_id", user.ID)
c.Set("username", user.Username)
c.Next()
}
}
// requireRole creates middleware that requires a specific role
func requireRole(roleName string) gin.HandlerFunc {
return func(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
c.Abort()
return
}
authUser, ok := user.(*iam.User)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
c.Abort()
return
}
// Load roles if not already loaded
if len(authUser.Roles) == 0 {
// Get DB from context (set by router)
db, exists := c.Get("db")
if exists {
if dbConn, ok := db.(*database.DB); ok {
roles, err := iam.GetUserRoles(dbConn, authUser.ID)
if err == nil {
authUser.Roles = roles
}
}
}
}
// Check if user has the required role
hasRole := false
for _, role := range authUser.Roles {
if role == roleName {
hasRole = true
break
}
}
if !hasRole {
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
c.Abort()
return
}
c.Next()
}
}
// requirePermission creates middleware that requires a specific permission
func requirePermission(resource, action string) gin.HandlerFunc {
return func(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
c.Abort()
return
}
authUser, ok := user.(*iam.User)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
c.Abort()
return
}
// Load permissions if not already loaded
if len(authUser.Permissions) == 0 {
// Get DB from context (set by router)
db, exists := c.Get("db")
if exists {
if dbConn, ok := db.(*database.DB); ok {
permissions, err := iam.GetUserPermissions(dbConn, authUser.ID)
if err == nil {
authUser.Permissions = permissions
}
}
}
}
// Check if user has the required permission
permissionName := resource + ":" + action
hasPermission := false
for _, perm := range authUser.Permissions {
if perm == permissionName {
hasPermission = true
break
}
}
if !hasPermission {
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
c.Abort()
return
}
c.Next()
}
}