postgres_store.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package postgres
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "time"
  6. "github.com/seaweedfs/seaweedfs/weed/credential"
  7. "github.com/seaweedfs/seaweedfs/weed/util"
  8. _ "github.com/jackc/pgx/v5/stdlib"
  9. )
  10. func init() {
  11. credential.Stores = append(credential.Stores, &PostgresStore{})
  12. }
  13. // PostgresStore implements CredentialStore using PostgreSQL
  14. type PostgresStore struct {
  15. db *sql.DB
  16. configured bool
  17. }
  18. func (store *PostgresStore) GetName() credential.CredentialStoreTypeName {
  19. return credential.StoreTypePostgres
  20. }
  21. func (store *PostgresStore) Initialize(configuration util.Configuration, prefix string) error {
  22. if store.configured {
  23. return nil
  24. }
  25. hostname := configuration.GetString(prefix + "hostname")
  26. port := configuration.GetInt(prefix + "port")
  27. username := configuration.GetString(prefix + "username")
  28. password := configuration.GetString(prefix + "password")
  29. database := configuration.GetString(prefix + "database")
  30. schema := configuration.GetString(prefix + "schema")
  31. sslmode := configuration.GetString(prefix + "sslmode")
  32. // Set defaults
  33. if hostname == "" {
  34. hostname = "localhost"
  35. }
  36. if port == 0 {
  37. port = 5432
  38. }
  39. if schema == "" {
  40. schema = "public"
  41. }
  42. if sslmode == "" {
  43. sslmode = "disable"
  44. }
  45. // Build pgx-optimized connection string
  46. // Note: prefer_simple_protocol=true is only needed for PgBouncer, not direct PostgreSQL connections
  47. connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s search_path=%s",
  48. hostname, port, username, password, database, sslmode, schema)
  49. db, err := sql.Open("pgx", connStr)
  50. if err != nil {
  51. return fmt.Errorf("failed to open database: %w", err)
  52. }
  53. // Test connection
  54. if err := db.Ping(); err != nil {
  55. db.Close()
  56. return fmt.Errorf("failed to ping database: %w", err)
  57. }
  58. // Set connection pool settings
  59. db.SetMaxOpenConns(25)
  60. db.SetMaxIdleConns(5)
  61. db.SetConnMaxLifetime(5 * time.Minute)
  62. store.db = db
  63. // Create tables if they don't exist
  64. if err := store.createTables(); err != nil {
  65. db.Close()
  66. return fmt.Errorf("failed to create tables: %w", err)
  67. }
  68. store.configured = true
  69. return nil
  70. }
  71. func (store *PostgresStore) createTables() error {
  72. // Create users table
  73. usersTable := `
  74. CREATE TABLE IF NOT EXISTS users (
  75. username VARCHAR(255) PRIMARY KEY,
  76. email VARCHAR(255),
  77. account_data JSONB,
  78. actions JSONB,
  79. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  80. updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  81. );
  82. CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
  83. `
  84. // Create credentials table
  85. credentialsTable := `
  86. CREATE TABLE IF NOT EXISTS credentials (
  87. id SERIAL PRIMARY KEY,
  88. username VARCHAR(255) REFERENCES users(username) ON DELETE CASCADE,
  89. access_key VARCHAR(255) UNIQUE NOT NULL,
  90. secret_key VARCHAR(255) NOT NULL,
  91. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  92. );
  93. CREATE INDEX IF NOT EXISTS idx_credentials_username ON credentials(username);
  94. CREATE INDEX IF NOT EXISTS idx_credentials_access_key ON credentials(access_key);
  95. `
  96. // Create policies table
  97. policiesTable := `
  98. CREATE TABLE IF NOT EXISTS policies (
  99. name VARCHAR(255) PRIMARY KEY,
  100. document JSONB NOT NULL,
  101. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  102. updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  103. );
  104. CREATE INDEX IF NOT EXISTS idx_policies_name ON policies(name);
  105. `
  106. // Execute table creation
  107. if _, err := store.db.Exec(usersTable); err != nil {
  108. return fmt.Errorf("failed to create users table: %w", err)
  109. }
  110. if _, err := store.db.Exec(credentialsTable); err != nil {
  111. return fmt.Errorf("failed to create credentials table: %w", err)
  112. }
  113. if _, err := store.db.Exec(policiesTable); err != nil {
  114. return fmt.Errorf("failed to create policies table: %w", err)
  115. }
  116. return nil
  117. }
  118. func (store *PostgresStore) Shutdown() {
  119. if store.db != nil {
  120. store.db.Close()
  121. store.db = nil
  122. }
  123. store.configured = false
  124. }