refactor: restructure library to expose public API directly
feat: add new helper methods for RAC operations docs: add comprehensive library usage documentation chore: move example to examples/library_usage directory
This commit is contained in:
322
benadis_rac_helpers.go
Normal file
322
benadis_rac_helpers.go
Normal file
@@ -0,0 +1,322 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user