feat: add new helper methods for RAC operations docs: add comprehensive library usage documentation chore: move example to examples/library_usage directory
322 lines
9.1 KiB
Go
322 lines
9.1 KiB
Go
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
|
|
} |