Skip to content

Commit 2349e23

Browse files
authored
feat: Phase 3 — PostgreSQL provider (#54)
feat: Phase 3 — PostgreSQL provider
2 parents b6fc4a3 + cadfe55 commit 2349e23

25 files changed

Lines changed: 1661 additions & 37 deletions

cmd/deploy_postgresql.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"path"
6+
7+
"github.com/ProxySQL/dbdeployer/common"
8+
"github.com/ProxySQL/dbdeployer/defaults"
9+
"github.com/ProxySQL/dbdeployer/providers"
10+
"github.com/ProxySQL/dbdeployer/providers/postgresql"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
func deploySandboxPostgreSQL(cmd *cobra.Command, args []string) {
15+
version := args[0]
16+
flags := cmd.Flags()
17+
skipStart, _ := flags.GetBool("skip-start")
18+
19+
p, err := providers.DefaultRegistry.Get("postgresql")
20+
if err != nil {
21+
common.Exitf(1, "PostgreSQL provider not available: %s", err)
22+
}
23+
24+
if err := p.ValidateVersion(version); err != nil {
25+
common.Exitf(1, "invalid version: %s", err)
26+
}
27+
28+
if _, err := p.FindBinary(version); err != nil {
29+
common.Exitf(1, "PostgreSQL binaries not found: %s\nRun: dbdeployer unpack --provider=postgresql <server.deb> <client.deb>", err)
30+
}
31+
32+
port, err := postgresql.VersionToPort(version)
33+
if err != nil {
34+
common.Exitf(1, "error computing port: %s", err)
35+
}
36+
freePort, portErr := common.FindFreePort(port, []int{}, 1)
37+
if portErr == nil {
38+
port = freePort
39+
}
40+
41+
sandboxHome := defaults.Defaults().SandboxHome
42+
sandboxDir := path.Join(sandboxHome, fmt.Sprintf("pg_sandbox_%d", port))
43+
44+
if common.DirExists(sandboxDir) {
45+
common.Exitf(1, "sandbox directory %s already exists", sandboxDir)
46+
}
47+
48+
config := providers.SandboxConfig{
49+
Version: version,
50+
Dir: sandboxDir,
51+
Port: port,
52+
Host: "127.0.0.1",
53+
DbUser: "postgres",
54+
DbPassword: "",
55+
Options: map[string]string{},
56+
}
57+
58+
if _, err := p.CreateSandbox(config); err != nil {
59+
common.Exitf(1, "error creating PostgreSQL sandbox: %s", err)
60+
}
61+
62+
if !skipStart {
63+
if err := p.StartSandbox(sandboxDir); err != nil {
64+
common.Exitf(1, "error starting PostgreSQL: %s", err)
65+
}
66+
}
67+
68+
fmt.Printf("PostgreSQL %s sandbox deployed in %s (port: %d)\n", version, sandboxDir, port)
69+
}
70+
71+
var deployPostgreSQLCmd = &cobra.Command{
72+
Use: "postgresql version",
73+
Short: "deploys a PostgreSQL sandbox",
74+
Long: `postgresql deploys a standalone PostgreSQL instance as a sandbox.
75+
It creates a sandbox directory with data, configuration, start/stop scripts, and a
76+
psql client script.
77+
78+
Requires PostgreSQL binaries to be extracted first:
79+
dbdeployer unpack --provider=postgresql postgresql-16_*.deb postgresql-client-16_*.deb
80+
81+
Example:
82+
dbdeployer deploy postgresql 16.13
83+
dbdeployer deploy postgresql 17.1 --skip-start
84+
`,
85+
Args: cobra.ExactArgs(1),
86+
Run: deploySandboxPostgreSQL,
87+
}
88+
89+
func init() {
90+
deployCmd.AddCommand(deployPostgreSQLCmd)
91+
deployPostgreSQLCmd.Flags().Bool("skip-start", false, "Do not start PostgreSQL after deployment")
92+
}

cmd/export_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func TestExportImport(t *testing.T) {
165165
subCommandName: "",
166166
expectedName: "deploy",
167167
expectedAncestors: 2,
168-
expectedSubCommands: 4,
168+
expectedSubCommands: 5,
169169
expectedArgument: "",
170170
},
171171
{
@@ -192,6 +192,14 @@ func TestExportImport(t *testing.T) {
192192
expectedSubCommands: 0,
193193
expectedArgument: globals.ExportVersionDir,
194194
},
195+
{
196+
commandName: "deploy",
197+
subCommandName: "postgresql",
198+
expectedName: "postgresql",
199+
expectedAncestors: 3,
200+
expectedSubCommands: 0,
201+
expectedArgument: "",
202+
},
195203
{
196204
commandName: "export",
197205
subCommandName: "",

cmd/multiple.go

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,106 @@
1616
package cmd
1717

1818
import (
19+
"fmt"
20+
"os"
21+
"path"
22+
"strings"
23+
1924
"github.com/ProxySQL/dbdeployer/common"
25+
"github.com/ProxySQL/dbdeployer/defaults"
2026
"github.com/ProxySQL/dbdeployer/globals"
2127
"github.com/ProxySQL/dbdeployer/providers"
28+
"github.com/ProxySQL/dbdeployer/providers/postgresql"
2229
"github.com/ProxySQL/dbdeployer/sandbox"
2330
"github.com/spf13/cobra"
2431
)
2532

33+
func deployMultipleNonMySQL(cmd *cobra.Command, args []string, providerName string) {
34+
flags := cmd.Flags()
35+
version := args[0]
36+
nodes, _ := flags.GetInt(globals.NodesLabel)
37+
38+
p, err := providers.DefaultRegistry.Get(providerName)
39+
if err != nil {
40+
common.Exitf(1, "provider error: %s", err)
41+
}
42+
43+
flavor, _ := flags.GetString(globals.FlavorLabel)
44+
if flavor != "" {
45+
common.Exitf(1, "--flavor is only valid with --provider=mysql")
46+
}
47+
48+
if !providers.ContainsString(p.SupportedTopologies(), "multiple") {
49+
common.Exitf(1, "provider %q does not support topology \"multiple\"\nSupported topologies: %s",
50+
providerName, strings.Join(p.SupportedTopologies(), ", "))
51+
}
52+
53+
if err := p.ValidateVersion(version); err != nil {
54+
common.Exitf(1, "version validation failed: %s", err)
55+
}
56+
57+
if _, err := p.FindBinary(version); err != nil {
58+
common.Exitf(1, "binaries not found: %s", err)
59+
}
60+
61+
basePort := p.DefaultPorts().BasePort
62+
if providerName == "postgresql" {
63+
basePort, _ = postgresql.VersionToPort(version)
64+
}
65+
66+
sandboxHome := defaults.Defaults().SandboxHome
67+
topologyDir := path.Join(sandboxHome, fmt.Sprintf("%s_multi_%d", providerName, basePort))
68+
if common.DirExists(topologyDir) {
69+
common.Exitf(1, "sandbox directory %s already exists", topologyDir)
70+
}
71+
os.MkdirAll(topologyDir, 0755)
72+
73+
skipStart, _ := flags.GetBool(globals.SkipStartLabel)
74+
75+
for i := 1; i <= nodes; i++ {
76+
port := basePort + i
77+
freePort, err := common.FindFreePort(port, []int{}, 1)
78+
if err == nil {
79+
port = freePort
80+
}
81+
82+
nodeDir := path.Join(topologyDir, fmt.Sprintf("node%d", i))
83+
config := providers.SandboxConfig{
84+
Version: version,
85+
Dir: nodeDir,
86+
Port: port,
87+
Host: "127.0.0.1",
88+
DbUser: "postgres",
89+
Options: map[string]string{},
90+
}
91+
92+
if _, err := p.CreateSandbox(config); err != nil {
93+
common.Exitf(1, "error creating node %d: %s", i, err)
94+
}
95+
96+
if !skipStart {
97+
if err := p.StartSandbox(nodeDir); err != nil {
98+
common.Exitf(1, "error starting node %d: %s", i, err)
99+
}
100+
}
101+
102+
fmt.Printf(" Node %d deployed in %s (port: %d)\n", i, nodeDir, port)
103+
}
104+
105+
fmt.Printf("%s multiple sandbox (%d nodes) deployed in %s\n", providerName, nodes, topologyDir)
106+
}
107+
26108
func multipleSandbox(cmd *cobra.Command, args []string) {
109+
flags := cmd.Flags()
110+
providerName, _ := flags.GetString(globals.ProviderLabel)
111+
112+
if providerName != "mysql" {
113+
deployMultipleNonMySQL(cmd, args, providerName)
114+
return
115+
}
116+
27117
var sd sandbox.SandboxDef
28118
common.CheckOrigin(args)
29-
flags := cmd.Flags()
30119
sd, err := fillSandboxDefinition(cmd, args, false)
31120
common.ErrCheckExitf(err, 1, "error filling sandbox definition")
32121
// Validate version with provider
@@ -69,4 +158,5 @@ Use the "unpack" command to get the tarball into the right directory.
69158
func init() {
70159
deployCmd.AddCommand(multipleCmd)
71160
multipleCmd.PersistentFlags().IntP(globals.NodesLabel, "n", globals.NodesValue, "How many nodes will be installed")
161+
multipleCmd.PersistentFlags().String(globals.ProviderLabel, globals.ProviderValue, "Database provider (mysql, postgresql)")
72162
}

0 commit comments

Comments
 (0)