working on bacula engine
This commit is contained in:
@@ -1694,14 +1694,12 @@ func (s *Service) ListStorageDaemons(ctx context.Context) ([]StorageDaemon, erro
|
||||
return nil, fmt.Errorf("Bacula database connection not configured")
|
||||
}
|
||||
|
||||
// Query only columns that exist in Storage table
|
||||
query := `
|
||||
SELECT
|
||||
s.StorageId,
|
||||
s.Name,
|
||||
s.Address,
|
||||
s.Port,
|
||||
s.DeviceName,
|
||||
s.MediaType
|
||||
s.Autochanger
|
||||
FROM Storage s
|
||||
ORDER BY s.Name
|
||||
`
|
||||
@@ -1715,33 +1713,29 @@ func (s *Service) ListStorageDaemons(ctx context.Context) ([]StorageDaemon, erro
|
||||
var daemons []StorageDaemon
|
||||
for rows.Next() {
|
||||
var daemon StorageDaemon
|
||||
var address, deviceName, mediaType sql.NullString
|
||||
var port sql.NullInt64
|
||||
var autochanger sql.NullInt64
|
||||
|
||||
err := rows.Scan(
|
||||
&daemon.StorageID, &daemon.Name, &address, &port,
|
||||
&deviceName, &mediaType,
|
||||
&daemon.StorageID, &daemon.Name, &autochanger,
|
||||
)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to scan storage daemon row", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if address.Valid {
|
||||
daemon.Address = address.String
|
||||
// Get detailed information from bconsole
|
||||
details, err := s.getStorageDaemonDetails(ctx, daemon.Name)
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to get storage daemon details from bconsole", "name", daemon.Name, "error", err)
|
||||
// Continue with defaults
|
||||
daemon.Status = "Unknown"
|
||||
} else {
|
||||
daemon.Address = details.Address
|
||||
daemon.Port = details.Port
|
||||
daemon.DeviceName = details.DeviceName
|
||||
daemon.MediaType = details.MediaType
|
||||
daemon.Status = details.Status
|
||||
}
|
||||
if port.Valid {
|
||||
daemon.Port = int(port.Int64)
|
||||
}
|
||||
if deviceName.Valid {
|
||||
daemon.DeviceName = deviceName.String
|
||||
}
|
||||
if mediaType.Valid {
|
||||
daemon.MediaType = mediaType.String
|
||||
}
|
||||
|
||||
// Default status to Online (could be enhanced with actual connection check)
|
||||
daemon.Status = "Online"
|
||||
|
||||
daemons = append(daemons, daemon)
|
||||
}
|
||||
@@ -1753,6 +1747,77 @@ func (s *Service) ListStorageDaemons(ctx context.Context) ([]StorageDaemon, erro
|
||||
return daemons, nil
|
||||
}
|
||||
|
||||
// getStorageDaemonDetails retrieves detailed information about a storage daemon using bconsole
|
||||
func (s *Service) getStorageDaemonDetails(ctx context.Context, storageName string) (*StorageDaemon, error) {
|
||||
bconsoleConfig := "/opt/calypso/conf/bacula/bconsole.conf"
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("echo -e 'show storage=%s\nquit' | bconsole -c %s", storageName, bconsoleConfig))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute bconsole: %w", err)
|
||||
}
|
||||
|
||||
// Parse bconsole output
|
||||
// Example output:
|
||||
// Autochanger: name=File1 address=localhost SDport=9103 MaxJobs=10 NumJobs=0
|
||||
// DeviceName=FileChgr1 MediaType=File1 StorageId=1 Autochanger=1
|
||||
outputStr := string(output)
|
||||
|
||||
daemon := &StorageDaemon{
|
||||
Name: storageName,
|
||||
Status: "Online", // Default, could check connection status
|
||||
}
|
||||
|
||||
// Parse address
|
||||
if idx := strings.Index(outputStr, "address="); idx != -1 {
|
||||
addrStart := idx + len("address=")
|
||||
addrEnd := strings.IndexAny(outputStr[addrStart:], " \n")
|
||||
if addrEnd == -1 {
|
||||
addrEnd = len(outputStr) - addrStart
|
||||
}
|
||||
daemon.Address = strings.TrimSpace(outputStr[addrStart : addrStart+addrEnd])
|
||||
}
|
||||
|
||||
// Parse port (SDport)
|
||||
if idx := strings.Index(outputStr, "SDport="); idx != -1 {
|
||||
portStart := idx + len("SDport=")
|
||||
portEnd := strings.IndexAny(outputStr[portStart:], " \n")
|
||||
if portEnd == -1 {
|
||||
portEnd = len(outputStr) - portStart
|
||||
}
|
||||
if port, err := strconv.Atoi(strings.TrimSpace(outputStr[portStart : portStart+portEnd])); err == nil {
|
||||
daemon.Port = port
|
||||
}
|
||||
}
|
||||
|
||||
// Parse DeviceName
|
||||
if idx := strings.Index(outputStr, "DeviceName="); idx != -1 {
|
||||
devStart := idx + len("DeviceName=")
|
||||
devEnd := strings.IndexAny(outputStr[devStart:], " \n")
|
||||
if devEnd == -1 {
|
||||
devEnd = len(outputStr) - devStart
|
||||
}
|
||||
daemon.DeviceName = strings.TrimSpace(outputStr[devStart : devStart+devEnd])
|
||||
}
|
||||
|
||||
// Parse MediaType
|
||||
if idx := strings.Index(outputStr, "MediaType="); idx != -1 {
|
||||
mediaStart := idx + len("MediaType=")
|
||||
mediaEnd := strings.IndexAny(outputStr[mediaStart:], " \n")
|
||||
if mediaEnd == -1 {
|
||||
mediaEnd = len(outputStr) - mediaStart
|
||||
}
|
||||
daemon.MediaType = strings.TrimSpace(outputStr[mediaStart : mediaStart+mediaEnd])
|
||||
}
|
||||
|
||||
// Check if storage is online by checking for connection errors in output
|
||||
if strings.Contains(outputStr, "ERR") || strings.Contains(outputStr, "Error") {
|
||||
daemon.Status = "Offline"
|
||||
}
|
||||
|
||||
return daemon, nil
|
||||
}
|
||||
|
||||
// CreatePoolRequest represents a request to create a new storage pool
|
||||
type CreatePoolRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
|
||||
Reference in New Issue
Block a user