add some changes
This commit is contained in:
@@ -156,6 +156,19 @@ func (h *Handler) ListClients(c *gin.Context) {
|
||||
// Parse search query
|
||||
opts.Search = c.Query("search")
|
||||
|
||||
// Parse category filter
|
||||
if category := c.Query("category"); category != "" {
|
||||
// Validate category
|
||||
validCategories := map[string]bool{
|
||||
"File": true,
|
||||
"Database": true,
|
||||
"Virtual": true,
|
||||
}
|
||||
if validCategories[category] {
|
||||
opts.Category = category
|
||||
}
|
||||
}
|
||||
|
||||
clients, err := h.service.ListClients(c.Request.Context(), opts)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list clients", "error", err)
|
||||
|
||||
@@ -84,6 +84,7 @@ type Client struct {
|
||||
Name string `json:"name"`
|
||||
Uname *string `json:"uname,omitempty"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Category *string `json:"category,omitempty"` // "File", "Database", "Virtual"
|
||||
AutoPrune *bool `json:"auto_prune,omitempty"`
|
||||
FileRetention *int64 `json:"file_retention,omitempty"`
|
||||
JobRetention *int64 `json:"job_retention,omitempty"`
|
||||
@@ -95,8 +96,9 @@ type Client struct {
|
||||
|
||||
// ListClientsOptions represents filtering options for clients
|
||||
type ListClientsOptions struct {
|
||||
Enabled *bool // Filter by enabled status (nil = all)
|
||||
Search string // Search by client name
|
||||
Enabled *bool // Filter by enabled status (nil = all)
|
||||
Search string // Search by client name
|
||||
Category string // Filter by category: "File", "Database", "Virtual" (empty = all)
|
||||
}
|
||||
|
||||
// DashboardStats represents statistics for the backup dashboard
|
||||
@@ -312,7 +314,8 @@ func (s *Service) queryBaculaDirect(ctx context.Context) ([]Job, error) {
|
||||
// syncFromBconsole syncs jobs using bconsole command (fallback method)
|
||||
func (s *Service) syncFromBconsole(ctx context.Context) error {
|
||||
// Execute bconsole command to list jobs
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", "echo -e 'list jobs\nquit' | bconsole")
|
||||
bconsoleConfig := "/opt/calypso/conf/bacula/bconsole.conf"
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("echo -e 'list jobs\nquit' | bconsole -c %s", bconsoleConfig))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -507,7 +510,8 @@ func (s *Service) parseBconsoleOutput(ctx context.Context, output string) []Job
|
||||
// getClientNameFromJob gets client name from job details using bconsole
|
||||
func (s *Service) getClientNameFromJob(ctx context.Context, jobID int) string {
|
||||
// Execute bconsole to get job details
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("echo -e 'list job jobid=%d\nquit' | bconsole", jobID))
|
||||
bconsoleConfig := "/opt/calypso/conf/bacula/bconsole.conf"
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("echo -e 'list job jobid=%d\nquit' | bconsole -c %s", jobID, bconsoleConfig))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -550,7 +554,9 @@ func (s *Service) ExecuteBconsoleCommand(ctx context.Context, command string) (s
|
||||
escapedCommand := strings.ReplaceAll(commandWithQuit, "'", "'\"'\"'")
|
||||
|
||||
// Execute bconsole command using printf to avoid echo -e issues
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("printf '%%s\\n' '%s' | bconsole", escapedCommand))
|
||||
// Use -c flag to specify config file location
|
||||
bconsoleConfig := "/opt/calypso/conf/bacula/bconsole.conf"
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("printf '%%s\\n' '%s' | bconsole -c %s", escapedCommand, bconsoleConfig))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -728,10 +734,94 @@ func (s *Service) queryClientsFromDatabase(ctx context.Context, opts ListClients
|
||||
return nil, fmt.Errorf("error iterating client rows: %w", err)
|
||||
}
|
||||
|
||||
// Load categories from Calypso database
|
||||
if err := s.loadClientCategories(ctx, clients); err != nil {
|
||||
s.logger.Warn("Failed to load client categories", "error", err)
|
||||
// Continue without categories, set default to "File"
|
||||
for i := range clients {
|
||||
if clients[i].Category == nil {
|
||||
defaultCategory := "File"
|
||||
clients[i].Category = &defaultCategory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by category if specified
|
||||
if opts.Category != "" {
|
||||
filtered := []Client{}
|
||||
for _, client := range clients {
|
||||
if client.Category != nil && *client.Category == opts.Category {
|
||||
filtered = append(filtered, client)
|
||||
}
|
||||
}
|
||||
clients = filtered
|
||||
}
|
||||
|
||||
s.logger.Debug("Queried clients from Bacula database", "count", len(clients))
|
||||
return clients, nil
|
||||
}
|
||||
|
||||
// loadClientCategories loads category information from Calypso database
|
||||
func (s *Service) loadClientCategories(ctx context.Context, clients []Client) error {
|
||||
if len(clients) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build query to get categories for all client IDs
|
||||
clientIDs := make([]interface{}, len(clients))
|
||||
for i, client := range clients {
|
||||
clientIDs[i] = client.ClientID
|
||||
}
|
||||
|
||||
// Create placeholders for IN clause
|
||||
placeholders := make([]string, len(clientIDs))
|
||||
args := make([]interface{}, len(clientIDs))
|
||||
for i := range clientIDs {
|
||||
placeholders[i] = fmt.Sprintf("$%d", i+1)
|
||||
args[i] = clientIDs[i]
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT client_id, category
|
||||
FROM client_metadata
|
||||
WHERE client_id IN (%s)
|
||||
`, strings.Join(placeholders, ","))
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
// Table might not exist yet (migration not run), return nil error
|
||||
if strings.Contains(err.Error(), "does not exist") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("failed to query client categories: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Create map of client_id -> category
|
||||
categoryMap := make(map[int]string)
|
||||
for rows.Next() {
|
||||
var clientID int
|
||||
var category string
|
||||
if err := rows.Scan(&clientID, &category); err != nil {
|
||||
continue
|
||||
}
|
||||
categoryMap[clientID] = category
|
||||
}
|
||||
|
||||
// Assign categories to clients
|
||||
for i := range clients {
|
||||
if category, exists := categoryMap[clients[i].ClientID]; exists {
|
||||
clients[i].Category = &category
|
||||
} else {
|
||||
// Default to "File" if no category found
|
||||
defaultCategory := "File"
|
||||
clients[i].Category = &defaultCategory
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// queryClientsFromBconsole queries clients using bconsole command (fallback method)
|
||||
func (s *Service) queryClientsFromBconsole(ctx context.Context, opts ListClientsOptions) ([]Client, error) {
|
||||
// Execute bconsole command to list clients
|
||||
@@ -752,6 +842,18 @@ func (s *Service) queryClientsFromBconsole(ctx context.Context, opts ListClients
|
||||
clients := s.parseBconsoleClientsOutput(output)
|
||||
s.logger.Debug("Parsed clients from bconsole", "count", len(clients))
|
||||
|
||||
// Load categories from Calypso database
|
||||
if err := s.loadClientCategories(ctx, clients); err != nil {
|
||||
s.logger.Warn("Failed to load client categories", "error", err)
|
||||
// Continue without categories, set default to "File"
|
||||
for i := range clients {
|
||||
if clients[i].Category == nil {
|
||||
defaultCategory := "File"
|
||||
clients[i].Category = &defaultCategory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply filters
|
||||
filtered := []Client{}
|
||||
for _, client := range clients {
|
||||
@@ -761,6 +863,11 @@ func (s *Service) queryClientsFromBconsole(ctx context.Context, opts ListClients
|
||||
if opts.Search != "" && !strings.Contains(strings.ToLower(client.Name), strings.ToLower(opts.Search)) {
|
||||
continue
|
||||
}
|
||||
if opts.Category != "" {
|
||||
if client.Category == nil || *client.Category != opts.Category {
|
||||
continue
|
||||
}
|
||||
}
|
||||
filtered = append(filtered, client)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user