Skip to content

Commit 09b8752

Browse files
authored
Merge pull request #1246 from planetscale/nick/storage-flags
Add --min-storage and --max-storage flags to database and branch creation
2 parents 4a39378 + 1fc64ba commit 09b8752

File tree

6 files changed

+245
-3
lines changed

6 files changed

+245
-3
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ require (
2525
github.com/mattn/go-shellwords v1.0.12
2626
github.com/mitchellh/go-homedir v1.1.0
2727
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
28-
github.com/planetscale/planetscale-go v0.160.0
28+
github.com/planetscale/planetscale-go v0.161.0
2929
github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4
3030
github.com/planetscale/psdbproxy v0.0.0-20250728082226-3f4ea3a74ec7
3131
github.com/spf13/cobra v1.10.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL
176176
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
177177
github.com/planetscale/noglog v0.2.1-0.20210421230640-bea75fcd2e8e h1:MZ8D+Z3m2vvqGZLvoQfpaGg/j1fNDr4j03s3PRz4rVY=
178178
github.com/planetscale/noglog v0.2.1-0.20210421230640-bea75fcd2e8e/go.mod h1:hwAsSPQdvPa3WcfKfzTXxtEq/HlqwLjQasfO6QbGo4Q=
179-
github.com/planetscale/planetscale-go v0.160.0 h1:nWgTrMJPk+FzV71OV+wKU17F6DCnSX0lHxHSUH6Yhn0=
180-
github.com/planetscale/planetscale-go v0.160.0/go.mod h1:paQCI5SgquuoewvMQM7R+r1XJO868bdP6/ihGidYRM0=
179+
github.com/planetscale/planetscale-go v0.161.0 h1:YWpOJXJTJKX2AFHoKkO/IZdRxCmOQAS+O6A+jJuteL8=
180+
github.com/planetscale/planetscale-go v0.161.0/go.mod h1:paQCI5SgquuoewvMQM7R+r1XJO868bdP6/ihGidYRM0=
181181
github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4 h1:Xv5pj20Rhfty1Tv0OVcidg4ez4PvGrpKvb6rvUwQgDs=
182182
github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4/go.mod h1:M52h5IWxAcbdQ1hSZrLAGQC4ZXslxEsK/Wh9nu3wdWs=
183183
github.com/planetscale/psdbproxy v0.0.0-20250728082226-3f4ea3a74ec7 h1:aRd6vdE1fyuSI4RVj7oCr8lFmgqXvpnPUmN85VbZCp8=

internal/cmd/branch/create.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
2121
clusterSize string
2222
backupID string
2323
majorVersion string
24+
minStorage int64
25+
maxStorage int64
2426
}
2527

2628
cmd := &cobra.Command{
@@ -103,6 +105,10 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
103105
}
104106

105107
if db.Kind == "mysql" {
108+
if cmd.Flags().Changed("min-storage") || cmd.Flags().Changed("max-storage") {
109+
return fmt.Errorf("--min-storage and --max-storage are only supported for PostgreSQL databases")
110+
}
111+
106112
createReq := &ps.CreateDatabaseBranchRequest{
107113
Organization: ch.Config.Organization,
108114
Database: source,
@@ -171,6 +177,16 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
171177
MajorVersion: flags.majorVersion,
172178
}
173179

180+
if cmd.Flags().Changed("min-storage") || cmd.Flags().Changed("max-storage") {
181+
createReq.Storage = &ps.StorageConfig{}
182+
if cmd.Flags().Changed("min-storage") {
183+
createReq.Storage.MinimumStorageBytes = &flags.minStorage
184+
}
185+
if cmd.Flags().Changed("max-storage") {
186+
createReq.Storage.MaximumStorageBytes = &flags.maxStorage
187+
}
188+
}
189+
174190
dbBranch, err := client.PostgresBranches.Create(cmd.Context(), createReq)
175191
if err != nil {
176192
switch cmdutil.ErrCode(err) {
@@ -224,6 +240,9 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
224240
cmd.Flags().BoolVar(&flags.dataBranching, "seed-data", false, "Add seed data using the Data Branching™ feature. This branch will be created with the same resources as the base branch.")
225241
cmd.Flags().BoolVar(&flags.wait, "wait", false, "Wait until the branch is ready")
226242
cmd.Flags().StringVar(&flags.majorVersion, "major-version", "", "For PostgreSQL databases, the PostgreSQL major version to use for the branch. Defaults to the major version of the parent branch if it exists or the database's default branch major version. Ignored for branches restored from backups.")
243+
cmd.Flags().Int64Var(&flags.minStorage, "min-storage", 0, "Minimum storage size in bytes")
244+
cmd.Flags().Int64Var(&flags.maxStorage, "max-storage", 0, "Maximum storage size in bytes for autoscaling")
245+
227246
cmd.MarkFlagsMutuallyExclusive("from", "restore")
228247
cmd.MarkFlagsMutuallyExclusive("restore", "seed-data")
229248

internal/cmd/branch/create_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,113 @@ func TestBranch_CreateCmdWithMajorVersion(t *testing.T) {
298298
c.Assert(buf.String(), qt.JSONEquals, res)
299299
}
300300

301+
func TestBranch_CreateCmdWithStorageMySQLError(t *testing.T) {
302+
c := qt.New(t)
303+
304+
var buf bytes.Buffer
305+
format := printer.JSON
306+
p := printer.NewPrinter(&format)
307+
p.SetResourceOutput(&buf)
308+
309+
org := "planetscale"
310+
db := "planetscale"
311+
branch := "development"
312+
313+
dbSvc := &mock.DatabaseService{
314+
GetFn: func(ctx context.Context, req *ps.GetDatabaseRequest) (*ps.Database, error) {
315+
return &ps.Database{Kind: "mysql"}, nil
316+
},
317+
}
318+
319+
svc := &mock.DatabaseBranchesService{
320+
CreateFn: func(ctx context.Context, req *ps.CreateDatabaseBranchRequest) (*ps.DatabaseBranch, error) {
321+
c.Fatal("CreateFn should not be called for MySQL with storage flags")
322+
return nil, nil
323+
},
324+
}
325+
326+
ch := &cmdutil.Helper{
327+
Printer: p,
328+
Config: &config.Config{
329+
Organization: org,
330+
},
331+
Client: func() (*ps.Client, error) {
332+
return &ps.Client{
333+
DatabaseBranches: svc,
334+
Databases: dbSvc,
335+
}, nil
336+
},
337+
}
338+
339+
cmd := CreateCmd(ch)
340+
cmd.SetArgs([]string{db, branch, "--region", "us-east", "--min-storage", "10737418240"})
341+
err := cmd.Execute()
342+
343+
c.Assert(err, qt.IsNotNil)
344+
c.Assert(err, qt.ErrorMatches, ".*only supported for PostgreSQL.*")
345+
c.Assert(svc.CreateFnInvoked, qt.IsFalse)
346+
}
347+
348+
func TestBranch_CreateCmdWithStorage(t *testing.T) {
349+
c := qt.New(t)
350+
351+
var buf bytes.Buffer
352+
format := printer.JSON
353+
p := printer.NewPrinter(&format)
354+
p.SetResourceOutput(&buf)
355+
356+
org := "planetscale"
357+
db := "planetscale"
358+
branch := "development"
359+
360+
res := &ps.PostgresBranch{Name: branch}
361+
362+
svc := &mock.PostgresBranchesService{
363+
CreateFn: func(ctx context.Context, req *ps.CreatePostgresBranchRequest) (*ps.PostgresBranch, error) {
364+
c.Assert(req.Name, qt.Equals, branch)
365+
c.Assert(req.Database, qt.Equals, db)
366+
c.Assert(req.Region, qt.Equals, "us-east")
367+
c.Assert(req.Organization, qt.Equals, org)
368+
c.Assert(req.Storage, qt.IsNotNil)
369+
c.Assert(req.Storage.MinimumStorageBytes, qt.IsNotNil)
370+
c.Assert(*req.Storage.MinimumStorageBytes, qt.Equals, int64(10737418240))
371+
c.Assert(req.Storage.MaximumStorageBytes, qt.IsNotNil)
372+
c.Assert(*req.Storage.MaximumStorageBytes, qt.Equals, int64(107374182400))
373+
374+
return res, nil
375+
},
376+
}
377+
378+
dbSvc := &mock.DatabaseService{
379+
GetFn: func(ctx context.Context, req *ps.GetDatabaseRequest) (*ps.Database, error) {
380+
c.Assert(req.Database, qt.Equals, db)
381+
c.Assert(req.Organization, qt.Equals, org)
382+
return &ps.Database{Kind: "postgresql"}, nil
383+
},
384+
}
385+
386+
ch := &cmdutil.Helper{
387+
Printer: p,
388+
Config: &config.Config{
389+
Organization: org,
390+
},
391+
Client: func() (*ps.Client, error) {
392+
return &ps.Client{
393+
PostgresBranches: svc,
394+
Databases: dbSvc,
395+
}, nil
396+
},
397+
}
398+
399+
cmd := CreateCmd(ch)
400+
cmd.SetArgs([]string{db, branch, "--region", "us-east", "--min-storage", "10737418240", "--max-storage", "107374182400"})
401+
err := cmd.Execute()
402+
403+
c.Assert(err, qt.IsNil)
404+
c.Assert(svc.CreateFnInvoked, qt.IsTrue)
405+
c.Assert(buf.String(), qt.JSONEquals, res)
406+
}
407+
301408
func TestBranch_CreateCmd_ServiceTokenAuthError(t *testing.T) {
302409
c := qt.New(t)
303410

internal/cmd/database/create.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
2424
wait bool
2525
replicas *int
2626
majorVersion string
27+
minStorage int64
28+
maxStorage int64
2729
}
2830

2931
cmd := &cobra.Command{
@@ -51,6 +53,20 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
5153
createReq.MajorVersion = flags.majorVersion
5254
}
5355

56+
if (cmd.Flags().Changed("min-storage") || cmd.Flags().Changed("max-storage")) && engine != ps.DatabaseEnginePostgres {
57+
return fmt.Errorf("--min-storage and --max-storage are only supported for PostgreSQL databases")
58+
}
59+
60+
if cmd.Flags().Changed("min-storage") || cmd.Flags().Changed("max-storage") {
61+
createReq.Storage = &ps.StorageConfig{}
62+
if cmd.Flags().Changed("min-storage") {
63+
createReq.Storage.MinimumStorageBytes = &flags.minStorage
64+
}
65+
if cmd.Flags().Changed("max-storage") {
66+
createReq.Storage.MaximumStorageBytes = &flags.maxStorage
67+
}
68+
}
69+
5470
client, err := ch.Client()
5571
if err != nil {
5672
return err
@@ -120,6 +136,9 @@ func CreateCmd(ch *cmdutil.Helper) *cobra.Command {
120136
cmd.RegisterFlagCompletionFunc("cluster-size", func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
121137
return cmdutil.ClusterSizesCompletionFunc(ch, cmd, args, toComplete)
122138
})
139+
cmd.Flags().Int64Var(&flags.minStorage, "min-storage", 0, "Minimum storage size in bytes")
140+
cmd.Flags().Int64Var(&flags.maxStorage, "max-storage", 0, "Maximum storage size in bytes for autoscaling")
141+
123142
cmd.Flags().BoolVar(&flags.wait, "wait", false, "Wait until the database is ready")
124143

125144
return cmd

internal/cmd/database/create_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,103 @@ func TestDatabase_CreateCmdWithReplicas(t *testing.T) {
228228
c.Assert(buf.String(), qt.JSONEquals, res)
229229
}
230230

231+
func TestDatabase_CreateCmdWithStorageMySQLError(t *testing.T) {
232+
c := qt.New(t)
233+
234+
var buf bytes.Buffer
235+
format := printer.JSON
236+
p := printer.NewPrinter(&format)
237+
p.SetResourceOutput(&buf)
238+
239+
org := "planetscale"
240+
db := "planetscale"
241+
242+
svc := &mock.DatabaseService{
243+
CreateFn: func(ctx context.Context, req *ps.CreateDatabaseRequest) (*ps.Database, error) {
244+
c.Fatal("CreateFn should not be called for MySQL with storage flags")
245+
return nil, nil
246+
},
247+
}
248+
249+
ch := &cmdutil.Helper{
250+
Printer: p,
251+
Config: &config.Config{
252+
Organization: org,
253+
},
254+
Client: func() (*ps.Client, error) {
255+
return &ps.Client{
256+
Databases: svc,
257+
}, nil
258+
},
259+
}
260+
261+
cmd := CreateCmd(ch)
262+
cmd.SetArgs([]string{db, "--region", "us-east", "--min-storage", "10737418240"})
263+
err := cmd.Execute()
264+
265+
c.Assert(err, qt.IsNotNil)
266+
c.Assert(err, qt.ErrorMatches, ".*only supported for PostgreSQL.*")
267+
c.Assert(svc.CreateFnInvoked, qt.IsFalse)
268+
}
269+
270+
func TestDatabase_CreateCmdWithStorage(t *testing.T) {
271+
c := qt.New(t)
272+
273+
var buf bytes.Buffer
274+
format := printer.JSON
275+
p := printer.NewPrinter(&format)
276+
p.SetResourceOutput(&buf)
277+
278+
org := "planetscale"
279+
db := "planetscale"
280+
281+
res := &ps.Database{Name: "foo"}
282+
283+
svc := &mock.DatabaseService{
284+
CreateFn: func(ctx context.Context, req *ps.CreateDatabaseRequest) (*ps.Database, error) {
285+
c.Assert(req.Organization, qt.Equals, org)
286+
c.Assert(req.Name, qt.Equals, db)
287+
c.Assert(req.Region, qt.Equals, "us-east")
288+
c.Assert(req.Kind, qt.Equals, ps.DatabaseEnginePostgres)
289+
c.Assert(req.Storage, qt.IsNotNil)
290+
c.Assert(req.Storage.MinimumStorageBytes, qt.IsNotNil)
291+
c.Assert(*req.Storage.MinimumStorageBytes, qt.Equals, int64(10737418240))
292+
c.Assert(req.Storage.MaximumStorageBytes, qt.IsNotNil)
293+
c.Assert(*req.Storage.MaximumStorageBytes, qt.Equals, int64(107374182400))
294+
295+
return res, nil
296+
},
297+
}
298+
299+
ch := &cmdutil.Helper{
300+
Printer: p,
301+
Config: &config.Config{
302+
Organization: org,
303+
},
304+
Client: func() (*ps.Client, error) {
305+
return &ps.Client{
306+
Databases: svc,
307+
Organizations: &mock.OrganizationsService{
308+
GetFn: func(ctx context.Context, request *ps.GetOrganizationRequest) (*ps.Organization, error) {
309+
return &ps.Organization{
310+
RemainingFreeDatabases: 1,
311+
Name: request.Organization,
312+
}, nil
313+
},
314+
},
315+
}, nil
316+
},
317+
}
318+
319+
cmd := CreateCmd(ch)
320+
cmd.SetArgs([]string{db, "--region", "us-east", "--engine", "postgresql", "--min-storage", "10737418240", "--max-storage", "107374182400"})
321+
err := cmd.Execute()
322+
323+
c.Assert(err, qt.IsNil)
324+
c.Assert(svc.CreateFnInvoked, qt.IsTrue)
325+
c.Assert(buf.String(), qt.JSONEquals, res)
326+
}
327+
231328
func TestDatabase_CreateCmdPostgresWithMajorVersion(t *testing.T) {
232329
c := qt.New(t)
233330

0 commit comments

Comments
 (0)