package benadis_rac import ( "context" "fmt" "regexp" "strings" ) // getClusterUUID получает UUID кластера func (c *Client) getClusterUUID(ctx context.Context) (string, error) { c.logger.Debug("Getting cluster UUID") args := []string{ c.config.RACPath, "cluster", "list", c.getRACAddress(), } output, err := c.executeCommand(ctx, args) if err != nil { return "", fmt.Errorf("failed to get cluster list: %w", err) } // Ищем UUID кластера в выводе uuidRegex := regexp.MustCompile(`cluster\s*:\s*([a-fA-F0-9-]{36})`) matches := uuidRegex.FindStringSubmatch(output) if len(matches) < 2 { return "", fmt.Errorf("cluster UUID not found in output") } clusterUUID := matches[1] c.logger.Debug("Found cluster UUID", "uuid", clusterUUID) return clusterUUID, nil } // getInfobaseUUID получает UUID информационной базы func (c *Client) getInfobaseUUID(ctx context.Context, clusterUUID string) (string, error) { c.logger.Debug("Getting infobase UUID", "cluster", clusterUUID) args := []string{ c.config.RACPath, "infobase", "summary", "list", "--cluster=" + clusterUUID, "--cluster-user=" + c.config.ClusterAdmin, "--cluster-pwd=" + c.config.ClusterAdminPassword, c.getRACAddress(), } output, err := c.executeCommand(ctx, args) if err != nil { return "", fmt.Errorf("failed to get infobase list: %w", err) } // Ищем информационную базу по имени lines := strings.Split(output, "\n") var currentInfobase string var currentUUID string for _, line := range lines { line = strings.TrimSpace(line) if strings.HasPrefix(line, "infobase") { // Извлекаем UUID из строки вида "infobase : uuid" parts := strings.Split(line, ":") if len(parts) >= 2 { currentUUID = strings.TrimSpace(parts[1]) } } else if strings.HasPrefix(line, "name") { // Извлекаем имя из строки вида "name : basename" parts := strings.Split(line, ":") if len(parts) >= 2 { currentInfobase = strings.TrimSpace(parts[1]) if currentInfobase == c.config.BaseName && currentUUID != "" { c.logger.Debug("Found infobase UUID", "uuid", currentUUID, "name", currentInfobase) return currentUUID, nil } } } } return "", fmt.Errorf("infobase UUID not found for name: %s", c.config.BaseName) } // setServiceMode устанавливает сервисный режим func (c *Client) setServiceMode(ctx context.Context, clusterUUID, infobaseUUID string, enable bool) error { var action string if enable { c.logger.Info("Enabling service mode") action = "on" } else { c.logger.Info("Disabling service mode") action = "off" } deniedMessage := c.config.DeniedMessage if deniedMessage == "" { deniedMessage = DefaultDeniedMessage } permissionCode := c.config.PermissionCode if permissionCode == "" { permissionCode = DefaultPermissionCode } args := []string{ c.config.RACPath, "infobase", "update", "--cluster=" + clusterUUID, "--infobase=" + infobaseUUID, "--cluster-user=" + c.config.ClusterAdmin, "--cluster-pwd=" + c.config.ClusterAdminPassword, "--infobase-user=" + c.config.DBAdmin, "--infobase-pwd=" + c.config.DBAdminPassword, "--sessions-deny=" + action, "--scheduled-jobs-deny=" + action, c.getRACAddress(), } if enable { args = append(args, "--denied-message="+deniedMessage) args = append(args, "--permission-code="+permissionCode) } _, err := c.executeCommand(ctx, args) if err != nil { if enable { return fmt.Errorf("failed to enable service mode: %w", err) } return fmt.Errorf("failed to disable service mode: %w", err) } return nil } // terminateAllSessions завершает все активные сессии func (c *Client) terminateAllSessions(ctx context.Context, clusterUUID, infobaseUUID string) error { c.logger.Info("Terminating all sessions") // Получаем список сессий sessions, err := c.getSessions(ctx, clusterUUID, infobaseUUID) if err != nil { return fmt.Errorf("failed to get sessions: %w", err) } if len(sessions) == 0 { c.logger.Info("No active sessions found") return nil } c.logger.Info("Found active sessions", "count", len(sessions)) // Завершаем каждую сессию for _, sessionID := range sessions { if err := c.terminateSession(ctx, clusterUUID, sessionID); err != nil { c.logger.Warn("Failed to terminate session", "session", sessionID, "error", err) continue } c.logger.Debug("Session terminated", "session", sessionID) } c.logger.Info("All sessions termination completed") return nil } // getSessions получает список активных сессий func (c *Client) getSessions(ctx context.Context, clusterUUID, infobaseUUID string) ([]string, error) { args := []string{ c.config.RACPath, "session", "list", "--cluster=" + clusterUUID, "--infobase=" + infobaseUUID, "--cluster-user=" + c.config.ClusterAdmin, "--cluster-pwd=" + c.config.ClusterAdminPassword, c.getRACAddress(), } output, err := c.executeCommand(ctx, args) if err != nil { return nil, fmt.Errorf("failed to get session list: %w", err) } // Парсим вывод для извлечения ID сессий var sessions []string lines := strings.Split(output, "\n") for _, line := range lines { line = strings.TrimSpace(line) if strings.HasPrefix(line, "session") { // Извлекаем UUID из строки вида "session : uuid" parts := strings.Split(line, ":") if len(parts) >= 2 { sessionID := strings.TrimSpace(parts[1]) if isValidUUID(sessionID) { sessions = append(sessions, sessionID) } } } } return sessions, nil } // terminateSession завершает конкретную сессию func (c *Client) terminateSession(ctx context.Context, clusterUUID, sessionID string) error { args := []string{ c.config.RACPath, "session", "terminate", "--cluster=" + clusterUUID, "--session=" + sessionID, "--cluster-user=" + c.config.ClusterAdmin, "--cluster-pwd=" + c.config.ClusterAdminPassword, "--message=" + TechnicalMaintenanceMessage, c.getRACAddress(), } _, err := c.executeCommand(ctx, args) if err != nil { return fmt.Errorf("failed to terminate session %s: %w", sessionID, err) } return nil } // verifyServiceMode проверяет статус сервисного режима func (c *Client) verifyServiceMode(ctx context.Context, clusterUUID, infobaseUUID string, expectedEnabled bool) error { c.logger.Debug("Verifying service mode", "expected_enabled", expectedEnabled) args := []string{ c.config.RACPath, "infobase", "info", "--cluster=" + clusterUUID, "--infobase=" + infobaseUUID, "--cluster-user=" + c.config.ClusterAdmin, "--cluster-pwd=" + c.config.ClusterAdminPassword, "--infobase-user=" + c.config.DBAdmin, "--infobase-pwd=" + c.config.DBAdminPassword, c.getRACAddress(), } output, err := c.executeCommand(ctx, args) if err != nil { return fmt.Errorf("failed to get infobase info: %w", err) } // Проверяем статус sessions-deny expectedSessionsDeny := "off" if expectedEnabled { expectedSessionsDeny = "on" } if !strings.Contains(output, "sessions-deny") || !strings.Contains(output, expectedSessionsDeny) { return fmt.Errorf("sessions-deny verification failed: expected %s, got output: %s", expectedSessionsDeny, output) } // Проверяем статус scheduled-jobs-deny expectedJobsDeny := "off" if expectedEnabled { expectedJobsDeny = "on" } if !strings.Contains(output, "scheduled-jobs-deny") || !strings.Contains(output, expectedJobsDeny) { return fmt.Errorf("scheduled-jobs-deny verification failed: expected %s, got output: %s", expectedJobsDeny, output) } c.logger.Debug("Service mode verification successful") return nil } // isValidUUID проверяет, является ли строка валидным UUID func isValidUUID(uuid string) bool { if len(uuid) != UUIDLength { return false } dashCount := strings.Count(uuid, "-") return dashCount == UUIDDashCount } // SetDefaults устанавливает значения по умолчанию для конфигурации func (c *Config) SetDefaults() { if c.ConnectionTimeout == 0 { c.ConnectionTimeout = DefaultConnectionTimeout } if c.CommandTimeout == 0 { c.CommandTimeout = DefaultCommandTimeout } if c.RetryCount == 0 { c.RetryCount = DefaultRetryCount } if c.RetryDelay == 0 { c.RetryDelay = DefaultRetryDelay } if c.RACPort == 0 { c.RACPort = DefaultRACPort } if c.DeniedMessage == "" { c.DeniedMessage = DefaultDeniedMessage } if c.PermissionCode == "" { c.PermissionCode = DefaultPermissionCode } } // Validate проверяет корректность конфигурации func (c *Config) Validate() error { if c.ServerHost == "" { return fmt.Errorf("server_host is required") } if c.RACPath == "" { return fmt.Errorf("rac_path is required") } if c.BaseName == "" { return fmt.Errorf("base_name is required") } if c.ClusterAdmin == "" { return fmt.Errorf("cluster_admin is required") } if c.DBAdmin == "" { return fmt.Errorf("db_admin is required") } return nil }